static int sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); int i, ret = 0; #ifdef CONFIG_GPIOLIB if (s->devtype->nr_gpio) { ret = gpiochip_remove(&s->gpio); if (ret) return ret; } #endif for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); uart_remove_one_port(&s->uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } mutex_destroy(&s->mutex); uart_unregister_driver(&s->uart); if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); return ret; }
static void sc16is7xx_shutdown(struct uart_port *port) { /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); sc16is7xx_power(port, 0); }
static int sc16is7xx_startup(struct uart_port *port) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; sc16is7xx_power(port, 1); /* Reset FIFOs*/ val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT; sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val); udelay(5); sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, SC16IS7XX_FCR_FIFO_BIT); /* Enable EFR */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); regcache_cache_bypass(s->regmap, true); /* Enable write access to enhanced features and internal clock div */ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, SC16IS7XX_EFR_ENABLE_BIT); /* Enable TCR/TLR */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, SC16IS7XX_MCR_TCRTLR_BIT); /* Configure flow control levels */ /* Flow control halt level 48, resume level 24 */ sc16is7xx_port_write(port, SC16IS7XX_TCR_REG, SC16IS7XX_TCR_RX_RESUME(24) | SC16IS7XX_TCR_RX_HALT(48)); regcache_cache_bypass(s->regmap, false); /* Now, initialize the UART */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); /* Enable the Rx and Tx FIFO */ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT, 0); /* Enable RX, TX, CTS change interrupts */ val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT | SC16IS7XX_IER_CTSI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); return 0; }
static void sc16is7xx_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { sc16is7xx_power(port, (state == UART_PM_STATE_ON) ? 1 : 0); }
static int sc16is7xx_probe(struct device *dev, struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq, unsigned long flags) { unsigned long freq, *pfreq = dev_get_platdata(dev); int i, ret; struct sc16is7xx_port *s; if (IS_ERR(regmap)) return PTR_ERR(regmap); /* Alloc port structure */ s = devm_kzalloc(dev, sizeof(*s) + sizeof(struct sc16is7xx_one) * devtype->nr_uart, GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; } s->clk = devm_clk_get(dev, NULL); if (IS_ERR(s->clk)) { if (pfreq) freq = *pfreq; else return PTR_ERR(s->clk); } else { freq = clk_get_rate(s->clk); } s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); /* Register UART driver */ s->uart.owner = THIS_MODULE; s->uart.dev_name = "ttySC"; s->uart.nr = devtype->nr_uart; ret = uart_register_driver(&s->uart); if (ret) { dev_err(dev, "Registering UART driver failed\n"); goto out_clk; } #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) { /* Setup GPIO cotroller */ s->gpio.owner = THIS_MODULE; s->gpio.dev = dev; s->gpio.label = dev_name(dev); s->gpio.direction_input = sc16is7xx_gpio_direction_input; s->gpio.get = sc16is7xx_gpio_get; s->gpio.direction_output = sc16is7xx_gpio_direction_output; s->gpio.set = sc16is7xx_gpio_set; s->gpio.base = -1; s->gpio.ngpio = devtype->nr_gpio; s->gpio.can_sleep = 1; ret = gpiochip_add(&s->gpio); if (ret) goto out_uart; } #endif mutex_init(&s->mutex); for (i = 0; i < devtype->nr_uart; ++i) { /* Initialize port data */ s->p[i].port.line = i; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_SC16IS7XX; s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; s->p[i].port.ops = &sc16is7xx_ops; /* Disable all interrupts */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); /* Initialize queue for changing mode */ INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ sc16is7xx_power(&s->p[i].port, 0); } /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, IRQF_ONESHOT | flags, dev_name(dev), s); if (!ret) return 0; mutex_destroy(&s->mutex); #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) gpiochip_remove(&s->gpio); out_uart: #endif uart_unregister_driver(&s->uart); out_clk: if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); return ret; }