/** * xuartps_clk_notitifer_cb - Clock notifier callback * @nb: Notifier block * @event: Notify event * @data: Notifier data * Returns NOTIFY_OK on success, NOTIFY_BAD on error. */ static int xuartps_clk_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { u32 ctrl_reg; struct uart_port *port; int locked = 0; struct clk_notifier_data *ndata = data; unsigned long flags = 0; struct xuartps *xuartps = to_xuartps(nb); port = xuartps->port; if (port->suspended) return NOTIFY_OK; switch (event) { case PRE_RATE_CHANGE: { u32 bdiv; u32 cd; int div8; /* * Find out if current baud-rate can be achieved with new clock * frequency. */ if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, &bdiv, &cd, &div8)) return NOTIFY_BAD; spin_lock_irqsave(&xuartps->port->lock, flags); /* Disable the TX and RX to set baud rate */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), XUARTPS_CR_OFFSET); spin_unlock_irqrestore(&xuartps->port->lock, flags); return NOTIFY_OK; } case POST_RATE_CHANGE: /* * Set clk dividers to generate correct baud with new clock * frequency. */ spin_lock_irqsave(&xuartps->port->lock, flags); locked = 1; port->uartclk = ndata->new_rate; xuartps->baud = xuartps_set_baud_rate(xuartps->port, xuartps->baud); /* fall through */ case ABORT_RATE_CHANGE: if (!locked) spin_lock_irqsave(&xuartps->port->lock, flags); /* Set TX/RX Reset */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), XUARTPS_CR_OFFSET); while (xuartps_readl(XUARTPS_CR_OFFSET) & (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) cpu_relax(); /* * Clear the RX disable and TX disable bits and then set the TX * enable bit and RX enable bit to enable the transmitter and * receiver. */ xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); xuartps_writel( (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), XUARTPS_CR_OFFSET); spin_unlock_irqrestore(&xuartps->port->lock, flags); return NOTIFY_OK; default: return NOTIFY_DONE; } }
/** * xuartps_set_termios - termios operations, handling data length, parity, * stop bits, flow control, baud rate * @port: Handle to the uart port structure * @termios: Handle to the input termios structure * @old: Values of the previously saved termios structure * **/ static void xuartps_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int cval = 0; unsigned int baud; unsigned long flags; unsigned int ctrl_reg, mode_reg; spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { xuartps_readl(XUARTPS_FIFO_OFFSET); } /* Disable the TX and RX to set baud rate */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), XUARTPS_CR_OFFSET); /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */ baud = uart_get_baud_rate(port, termios, old, 0, 10000000); baud = xuartps_set_baud_rate(port, baud); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), XUARTPS_CR_OFFSET); ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); /* Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ xuartps_writel( (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), XUARTPS_CR_OFFSET); xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; port->ignore_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; /* ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; mode_reg = xuartps_readl(XUARTPS_MR_OFFSET); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { case CS6: cval |= XUARTPS_MR_CHARLEN_6_BIT; break; case CS7: cval |= XUARTPS_MR_CHARLEN_7_BIT; break; default: case CS8: cval |= XUARTPS_MR_CHARLEN_8_BIT; termios->c_cflag &= ~CSIZE; termios->c_cflag |= CS8; break; } /* Handling Parity and Stop Bits length */ if (termios->c_cflag & CSTOPB) cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */ else cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */ if (termios->c_cflag & PARENB) { /* Mark or Space parity */ if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) cval |= XUARTPS_MR_PARITY_MARK; else cval |= XUARTPS_MR_PARITY_SPACE; } else if (termios->c_cflag & PARODD) cval |= XUARTPS_MR_PARITY_ODD; else cval |= XUARTPS_MR_PARITY_EVEN; } else cval |= XUARTPS_MR_PARITY_NONE; xuartps_writel(cval , XUARTPS_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); }
/* * no clue yet how to implement this. i think we need access to the port * structure in this function to do the required changes. but i don't know how * to get it in here. * * Think I got it. port must have a notifier_block* member from where we then * can get to the outer port structure with a container_of() call. * * Not sure when to stop UART. probably it's enough to stop, reconfigure, start * in POST_RATE_CHANGE */ static int xuartps_clk_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { struct clk_notifier_data *ndata = data; struct uart_port *port; struct xuartps *xuartps = to_xuartps(nb); port = xuartps->port; switch (event) { case PRE_RATE_CHANGE: { u32 bdiv; u32 cd; int div8; /* Find out if current baud-rate can be achieved with new clock * frequency. */ if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, &bdiv, &cd, &div8)) return NOTIFY_BAD; return NOTIFY_OK; } case POST_RATE_CHANGE: /* Set clk dividers to generate correct baud with new clock * frequency. */ { u32 ctrl_reg; unsigned long flags = 0; spin_lock_irqsave(&xuartps->port->lock, flags); port->uartclk = ndata->new_rate; /* Empty the receive FIFO 1st before making changes */ while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) xuartps_readl(XUARTPS_FIFO_OFFSET); /* Disable the TX and RX to set baud rate */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), XUARTPS_CR_OFFSET); xuartps->baud = xuartps_set_baud_rate(xuartps->port, xuartps->baud); /* Set TX/RX Reset */ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), XUARTPS_CR_OFFSET); /* * Clear the RX disable and TX disable bits and then set the TX * enable bit and RX enable bit to enable the transmitter and * receiver. */ ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); xuartps_writel( (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), XUARTPS_CR_OFFSET); spin_unlock_irqrestore(&xuartps->port->lock, flags); return NOTIFY_OK; } case ABORT_RATE_CHANGE: return NOTIFY_OK; default: return NOTIFY_DONE; } }