[PATCH] tty/serial : Add I2C support to Max310x driver (linux-3.8.13)
From: <hidden>
Date: 2016-09-07 09:05:44
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<mailto:MeghanSaitwal@Eaton.com> Tested-by: Devidas Kalane DevidasKalane@Eaton.com<mailto:DevidasKalane@Eaton.com> Suggested-by: Ashwin Patwekar AshwinPatwekar@Eaton.com<mailto: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.oobj-$(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 <linux/regmap.h> #include <linux/gpio.h> #include <linux/spi/spi.h> +#include <linux/i2c.h> #include <linux/platform_data/max310x.h> +#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 maxstatic 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 <shc_work@mail.ru<mailto:shc_work@mail.ru>>");