MAX3107/8 chip supports both SPI and I2C protocol. Currently, max310x driver support only SPI protocol. This patch adds I2C support to the driver. With I2C support, we have added bulk read/write functionality which can be enabled using BULK_RW_ENABLE variable. Signed-off-by: Meghan Saitwal MeghanSaitwal@Eaton.com Tested-by: Devidas Kalane DevidasKalane@Eaton.com Suggested-by: Ashwin Patwekar AshwinPatwekar@Eaton.com drivers/tty/serial/Kconfig | 38 +++- drivers/tty/serial/Makefile | 2 drivers/tty/serial/max310x.c | 268 +++++++++++++++++++++++++++------ 3 files changed, 254 insertions(+), 54 deletions(-) diff -purN a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig --- a/drivers/tty/serial/Kconfig 2016-09-01 12:05:32.092474214 +0530 +++ b/drivers/tty/serial/Kconfig 2016-09-01 12:11:12.938507208 +0530 @@ -276,19 +276,45 @@ config SERIAL_MAX3100 help MAX3100 chip support +config SERIAL_MAX310X_CORE + tristate + config SERIAL_MAX310X - bool "MAX310X support" - depends on SPI + tristate "MAX310X support" + depends on (SPI && !I2C) || I2C select SERIAL_CORE - select REGMAP_SPI if SPI - default n help This selects support for an advanced UART from Maxim (Dallas). Supported ICs are MAX3107, MAX3108. Each IC contains 128 words each of receive and transmit FIFO - that can be controlled through I2C or high-speed SPI. + that can be controlled through I2C or high-speed SPI. + Select SPI or I2C bus using options below. + +config SERIAL_MAX310X_SPI + bool "MAX310x for spi interface" + depends on SERIAL_MAX310X + depends on SPI + select SERIAL_MAX310X_CORE if SERIAL_MAX310X + select REGMAP_SPI if SPI + default y + help + Enable MAX310x driver on SPI bus, + If required say y, and say n to spi if not required, + Enabled by default to support oldconfig. + You must select at least one bus for the driver to be built. + +config SERIAL_MAX310X_I2C + bool "MAX310x for I2C interface" + depends on SERIAL_MAX310X + depends on I2C + select SERIAL_MAX310XX_CORE if SERIAL_MAX310X + select REGMAP_I2C if I2C + help + Enable MAX310x driver on I2C bus, + If required say y, and say n to i2c if not required, + This is additional support to existing driver. + You must select at least one bus for the driver to be built. - Say Y here if you want to support this ICs. config SERIAL_DZ bool "DECstation DZ serial driver" diff -purN a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile --- a/drivers/tty/serial/Makefile 2016-09-01 12:07:31.815485804 +0530 +++ b/drivers/tty/serial/Makefile 2016-09-01 12:11:40.576509884 +0530 @@ -28,7 +28,7 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX310X) += max310x.o +obj-$(CONFIG_SERIAL_MAX310X_CORE) += max310x.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o diff -purN a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c --- a/drivers/tty/serial/max310x.c 2013-05-12 02:27:46.000000000 +0530 +++ b/drivers/tty/serial/max310x.c 2016-08-12 10:22:40.000000000 +0530 @@ -25,8 +25,11 @@ #include #include #include +#include #include +#define BULK_RW_ENABLE 0 + #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 @@ -272,6 +275,8 @@ struct max310x_port { const char *name; int uartclk; + unsigned char buf[MAX310X_FIFO_SIZE]; + unsigned int nr_gpio; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; @@ -459,7 +464,7 @@ static int max310x_set_ref_clk(struct ma static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen) { - unsigned int sts = 0, ch = 0, flag; + unsigned int sts = 0, ch = 0, flag, bytes_read, i; struct tty_struct *tty = tty_port_tty_get(&s->port.state->port); if (!tty) @@ -473,7 +478,64 @@ static void max310x_handle_rx(struct max dev_dbg(s->port.dev, "RX Len = %u\n", rxlen); - while (rxlen--) { + #if BULK_RW_ENABLE + + while (rxlen) { + regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts); + sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + if(sts) + { + regmap_read(s->regmap,MAX310X_RHR_REG, s->buf); + bytes_read = 1; + } else { + regcache_cache_bypass(s->regmap, true); + regmap_raw_read(s->regmap, MAX310X_RHR_REG, s->buf, rxlen); + regcache_cache_bypass(s->regmap, false); + bytes_read = rxlen; + } + + s->port.icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sts)) { + if (sts & MAX310X_LSR_RXBRK_BIT) { + s->port.icount.brk++; + if (uart_handle_break(&s->port)) + continue; + } else if (sts & MAX310X_LSR_RXPAR_BIT) + s->port.icount.parity++; + else if (sts & MAX310X_LSR_FRERR_BIT) + s->port.icount.frame++; + else if (sts & MAX310X_LSR_RXOVR_BIT) + s->port.icount.overrun++; + + sts &= s->port.read_status_mask; + if (sts & MAX310X_LSR_RXBRK_BIT) + flag = TTY_BREAK; + else if (sts & MAX310X_LSR_RXPAR_BIT) + flag = TTY_PARITY; + else if (sts & MAX310X_LSR_FRERR_BIT) + flag = TTY_FRAME; + else if (sts & MAX310X_LSR_RXOVR_BIT) + flag = TTY_OVERRUN; + } + + for(i=0; i< bytes_read; i++) + { + if (uart_handle_sysrq_char(s->port, s->buf[i])) + continue; + + if (sts & s->port.ignore_status_mask) + continue; + + uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT, + s->buf[i], flag); + } + rxlen -= bytes_read; + } + #else + while (rxlen--) { regmap_read(s->regmap, MAX310X_RHR_REG, &ch); regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts); @@ -514,8 +576,8 @@ static void max310x_handle_rx(struct max uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag); - } - + } + #endif tty_flip_buffer_push(tty); tty_kref_put(tty); @@ -524,8 +586,7 @@ static void max310x_handle_rx(struct max static void max310x_handle_tx(struct max310x_port *s) { struct circ_buf *xmit = &s->port.state->xmit; - unsigned int txlen = 0, to_send; - + unsigned int txlen = 0, to_send = 0, i; if (unlikely(s->port.x_char)) { regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char); s->port.icount.tx++; @@ -545,7 +606,18 @@ static void max310x_handle_tx(struct max to_send = (to_send > txlen) ? txlen : to_send; dev_dbg(s->port.dev, "TX Len = %u\n", to_send); - +#if BULK_RW_ENABLE + /* Add data to send */ + s->port.icount.tx += to_send; + for(i=0; i < to_send; ++i) + { + s->buf[i] = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } + regcache_cache_bypass(s->regmap, true); + regmap_raw_write(s->regmap, MAX310X_THR_REG, s->buf, to_send); + regcache_cache_bypass(s->regmap, false); +#else /* Add data to send */ s->port.icount.tx += to_send; while (to_send--) { @@ -553,6 +625,7 @@ static void max310x_handle_tx(struct max xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); }; +#endif } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -593,7 +666,7 @@ static irqreturn_t max310x_ist(int irq, static void max310x_wq_proc(struct work_struct *ws) { struct max310x_port *s = container_of(ws, struct max310x_port, tx_work); - + mutex_lock(&s->max310x_mutex); max310x_handle_tx(s); mutex_unlock(&s->max310x_mutex); @@ -887,12 +960,12 @@ static struct uart_ops max310x_ops = { .verify_port = max310x_verify_port, }; -static int max310x_suspend(struct spi_device *spi, pm_message_t state) +static int max310x_suspend(struct device *dev) { int ret; - struct max310x_port *s = dev_get_drvdata(&spi->dev); + struct max310x_port *s = dev_get_drvdata(dev); - dev_dbg(&spi->dev, "Suspend\n"); + dev_dbg(dev, "Suspend\n"); ret = uart_suspend_port(&s->uart, &s->port); @@ -911,11 +984,11 @@ static int max310x_suspend(struct spi_de return ret; } -static int max310x_resume(struct spi_device *spi) +static int max310x_resume(struct device *dev) { - struct max310x_port *s = dev_get_drvdata(&spi->dev); + struct max310x_port *s = dev_get_drvdata(dev); - dev_dbg(&spi->dev, "Resume\n"); + dev_dbg(dev, "Resume\n"); if (s->pdata->suspend) s->pdata->suspend(0); @@ -995,17 +1068,15 @@ static struct max310x_pdata generic_plat .frequency = 26000000, }; -static int max310x_probe(struct spi_device *spi) +static int max310x_probe(struct device *dev, int chiptype, struct regmap *regmap, int irq) { struct max310x_port *s; - struct device *dev = &spi->dev; - int chiptype = spi_get_device_id(spi)->driver_data; struct max310x_pdata *pdata = dev->platform_data; unsigned int val = 0; int ret; /* Check for IRQ */ - if (spi->irq <= 0) { + if (irq <= 0) { dev_err(dev, "No IRQ specified\n"); return -ENOTSUPP; } @@ -1023,6 +1094,7 @@ static int max310x_probe(struct spi_devi pdata = &generic_plat_data; } s->pdata = pdata; + s->regmap = regmap; /* Individual chip settings */ switch (chiptype) { @@ -1030,13 +1102,11 @@ static int max310x_probe(struct spi_devi s->name = "MAX3107"; s->nr_gpio = 4; s->uart.nr = 1; - s->regcfg.max_register = 0x1f; break; case MAX310X_TYPE_MAX3108: s->name = "MAX3108"; s->nr_gpio = 4; s->uart.nr = 1; - s->regcfg.max_register = 0x1e; break; default: dev_err(dev, "Unsupported chip type %i\n", chiptype); @@ -1054,32 +1124,16 @@ static int max310x_probe(struct spi_devi mutex_init(&s->max310x_mutex); - /* Setup SPI bus */ - spi->mode = SPI_MODE_0; - spi->bits_per_word = 8; - spi->max_speed_hz = 26000000; - spi_setup(spi); - - /* Setup regmap */ - s->regcfg.reg_bits = 8; - s->regcfg.val_bits = 8; - s->regcfg.read_flag_mask = 0x00; - s->regcfg.write_flag_mask = 0x80; - s->regcfg.cache_type = REGCACHE_RBTREE; - s->regcfg.writeable_reg = max3107_8_reg_writeable; - s->regcfg.volatile_reg = max310x_reg_volatile; - s->regcfg.precious_reg = max310x_reg_precious; - s->regmap = devm_regmap_init_spi(spi, &s->regcfg); if (IS_ERR(s->regmap)) { ret = PTR_ERR(s->regmap); dev_err(dev, "Failed to initialize register map\n"); goto err_out; } - /* Reset chip & check SPI function */ + /* Reset chip & check SPI/I2C function */ ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); if (ret) { - dev_err(dev, "SPI transfer failed\n"); + dev_err(dev, "SPI/I2C transfer failed\n"); goto err_out; } /* Clear chip reset */ @@ -1129,11 +1183,12 @@ static int max310x_probe(struct spi_devi regmap_write(s->regmap, MAX310X_MODE1_REG, val); /* Setup interrupt */ - ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist, + /* Used IRQF_TRIGGER_LOW in case of I2C */ + ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), s); if (ret) { - dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq); + dev_err(dev, "Unable to reguest IRQ %i\n", irq); goto err_out; } @@ -1156,7 +1211,7 @@ static int max310x_probe(struct spi_devi /* Initialize UART port data */ s->port.line = 0; s->port.dev = dev; - s->port.irq = spi->irq; + s->port.irq = irq; s->port.type = PORT_MAX310X; s->port.fifosize = MAX310X_FIFO_SIZE; s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; @@ -1203,9 +1258,8 @@ err_out: return ret; } -static int max310x_remove(struct spi_device *spi) +static int max310x_remove(struct device *dev) { - struct device *dev = &spi->dev; struct max310x_port *s = dev_get_drvdata(dev); int ret = 0; @@ -1237,6 +1291,63 @@ static int max310x_remove(struct spi_dev return ret; } +static struct regmap_config regcfg = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0x00, + .write_flag_mask = 0x80, // may need to remove this mask + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max3107_8_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, +}; + +#ifdef CONFIG_SERIAL_MAX310X_SPI + +static int max310x_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + int chiptype = spi_get_device_id(spi)->driver_data; + + /* Setup SPI bus */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + spi->max_speed_hz = 26000000; + spi_setup(spi); + + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + regcfg.max_register = 0x1f; + break; + case MAX310X_TYPE_MAX3108: + regcfg.max_register = 0x1e; + break; + default: + dev_err(&spi->dev, "Unsupported chip type %i\n", chiptype); + return -ENOTSUPP; + } + + + regmap = devm_regmap_init_spi(spi, ®cfg); + + return max310x_probe(&spi->dev, chiptype, regmap, spi->irq); +} + +static int max310x_spi_remove(struct spi_device *spi) +{ + return max310x_remove(&spi->dev); +} + +static int max310x_suspend(struct spi_device *spi, pm_message_t state) +{ + return max310x_suspend(&spi->dev); +} + +static int max310x_resume(struct spi_device *spi) +{ + return max310x_resume(&spi->dev); +} + static const struct spi_device_id max310x_id_table[] = { { "max3107", MAX310X_TYPE_MAX3107 }, { "max3108", MAX310X_TYPE_MAX3108 }, @@ -1249,13 +1360,76 @@ static struct spi_driver max310x_driver .name = "max310x", .owner = THIS_MODULE, }, - .probe = max310x_probe, - .remove = max310x_remove, - .suspend = max310x_suspend, - .resume = max310x_resume, + .probe = max310x_spi_probe, + .remove = max310x_spi_remove, + .suspend = max310x_spi_suspend, + .resume = max310x_spi_resume, .id_table = max310x_id_table, }; module_spi_driver(max310x_driver); +#endif + +#ifdef CONFIG_SERIAL_MAX310X_I2C + +static int max310x_i2c_probe(struct i2c_client *i2c,const struct i2c_device_id *id) +{ + struct regmap *regmap; + int chiptype = id->driver_data; + printk("chiptype = %d \n",chiptype); + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + regcfg.max_register = 0x1f; + break; + case MAX310X_TYPE_MAX3108: + regcfg.max_register = 0x1e; + break; + default: + dev_err(&i2c->dev, "Unsupported chip type %i\n", chiptype); + return -ENOTSUPP; + } + + + regmap = devm_regmap_init_i2c(i2c, ®cfg); + + return max310x_probe(&i2c->dev, chiptype, regmap, i2c->irq); +} + +static int max310x_i2c_remove(struct i2c_client *i2c) +{ + return max310x_remove(&i2c->dev); +} + +static int max310x_i2c_suspend(struct i2c_client *i2c, pm_message_t state) +{ + return max310x_suspend(&i2c->dev); +} + +static int max310x_i2c_resume(struct i2c_client *i2c) +{ + return max310x_resume(&i2c->dev); +} + + +static const struct i2c_device_id max310x_id_table[] = { + { "max3107", MAX310X_TYPE_MAX3107 }, + { "max3108", MAX310X_TYPE_MAX3108 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max310x_id_table); + +static struct i2c_driver max310x_driver = { + .driver = { + .name = "max310x", + .owner = THIS_MODULE, + }, + .probe = max310x_i2c_probe, + .remove = max310x_i2c_remove, + .suspend = max310x_i2c_suspend, + .resume = max310x_i2c_resume, + .id_table = max310x_id_table, +}; +module_i2c_driver(max310x_driver); +#endif MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Alexander Shiyan >");