[PATCH] tty/serial : Add I2C support to Max310x driver (linux-3.8.13)
MeghanSaitwal at Eaton.com
MeghanSaitwal at Eaton.com
Wed Sep 7 19:05:36 AEST 2016
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 at Eaton.com<mailto:MeghanSaitwal at Eaton.com>
Tested-by: Devidas Kalane DevidasKalane at Eaton.com<mailto:DevidasKalane at Eaton.com>
Suggested-by: Ashwin Patwekar AshwinPatwekar at Eaton.com<mailto:AshwinPatwekar at 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 <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 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 <shc_work at mail.ru<mailto:shc_work at mail.ru>>");
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20160907/f3175221/attachment-0001.html>
More information about the Linuxppc-dev
mailing list