Message ID | 1346844964-24839-1-git-send-email-sourav.poddar@ti.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 9/5/2012 5:06 PM, Sourav Poddar wrote: > smsc ece1099 is a keyboard scan or gpio expansion device. > The patch create keypad and gpio expander child for this > multi function smsc driver. > > Cc: Samuel Ortiz <sameo@linux.intel.com> > Cc: Benoit Cousson <b-cousson@ti.com> > Cc: Felipe Balbi <balbi@ti.com> > Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> > Signed-off-by: Sourav Poddar <sourav.poddar@ti.com> > --- > Changes since v1: > - Use Kconfig option correctly > - Add regmap_config paramters > - Modify formatting of logs for devid > - Move read/write function to headed file as an inline > function. > Documentation/smsc_ece1099.txt | 56 ++++++++++++++++++++ > drivers/mfd/Kconfig | 12 ++++ > drivers/mfd/Makefile | 1 + > drivers/mfd/smsc-ece1099.c | 110 +++++++++++++++++++++++++++++++++++++++ > include/linux/mfd/smsc.h | 111 ++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 290 insertions(+), 0 deletions(-) > create mode 100644 Documentation/smsc_ece1099.txt > create mode 100644 drivers/mfd/smsc-ece1099.c > create mode 100644 include/linux/mfd/smsc.h > > diff --git a/Documentation/smsc_ece1099.txt b/Documentation/smsc_ece1099.txt > new file mode 100644 > index 0000000..6b492e8 > --- /dev/null > +++ b/Documentation/smsc_ece1099.txt > @@ -0,0 +1,56 @@ > +What is smsc-ece1099? > +---------------------- > + > +The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion > +or GPIO Expansion device. The device supports a keyboard > +scan matrix of 23x8. The device is connected to a Master > +via the SMSC BC-Link interface or via the SMBus. > +Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals > +are multiplexed with GPIOs. > + > +Interrupt generation > +-------------------- > + > +Interrupts can be generated by an edge detection on a GPIO > +pin or an edge detection on one of the bus interface pins. > +Interrupts can also be detected on the keyboard scan interface. > +The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if > +any bit in one of the Interrupt Status registers is 1 and > +the corresponding Interrupt Mask bit is also 1. > + > +In order for software to determine which device is the source > +of an interrupt, it should first read the Group Interrupt Status Register > +to determine which Status register group is a source for the interrupt. > +Software should read both the Status register and the associated Mask register, > +then AND the two values together. Bits that are 1 in the result of the AND > +are active interrupts. Software clears an interrupt by writing a 1 to the > +corresponding bit in the Status register. > + > +Communication Protocol > +---------------------- > + > +- SMbus slave Interface > + The host processor communicates with the ECE1099 device > + through a series of read/write registers via the SMBus > + interface. SMBus is a serial communication protocol between > + a computer host and its peripheral devices. The SMBus data > + rate is 10KHz minimum to 400 KHz maximum > + > +- Slave Bus Interface > + The ECE1099 device SMBus implementation is a subset of the > + SMBus interface to the host. The device is a slave-only SMBus device. > + The implementation in the device is a subset of SMBus since it > + only supports four protocols. > + > + The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the > + only valid SMBus protocols for the device. > + > +- BC-LinkTM Interface > + The BC-Link is a proprietary bus that allows communication > + between a Master device and a Companion device. The Master > + device uses this serial bus to read and write registers > + located on the Companion device. The bus comprises three signals, > + BC_CLK, BC_DAT and BC_INT#. The Master device always provides the > + clock, BC_CLK, and the Companion device is the source for an > + independent asynchronous interrupt signal, BC_INT#. The ECE1099 > + supports BC-Link speeds up to 24MHz. > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index d1facef..991ef15 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -385,6 +385,18 @@ config MFD_T7L66XB > help > Support for Toshiba Mobile IO Controller T7L66XB > > +config MFD_SMSC > + bool "Support for the SMSC ECE1099 series chips" > + depends on I2C=y > + select MFD_CORE > + select REGMAP_I2C > + help > + If you say yes here you get support for the > + ece1099 chips from SMSC. > + > + To compile this driver as a module, choose M here: the > + module will be called smsc. > + > config MFD_TC6387XB > bool "Support Toshiba TC6387XB" > depends on ARM && HAVE_CLK > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > index 79dd22d..f587d91 100644 > --- a/drivers/mfd/Makefile > +++ b/drivers/mfd/Makefile > @@ -77,6 +77,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o > obj-$(CONFIG_MCP) += mcp-core.o > obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o > obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o > +obj-$(CONFIG_MFD_SMSC) += smsc.o > obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o > > ifeq ($(CONFIG_SA1100_ASSABET),y) > diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c > new file mode 100644 > index 0000000..73a6cb7 > --- /dev/null > +++ b/drivers/mfd/smsc-ece1099.c > @@ -0,0 +1,110 @@ > +/* > + * TI SMSC MFD Driver > + * > + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com > + * > + * Author: Sourav Poddar <sourav.poddar@ti.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; GPL v2. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/moduleparam.h> > +#include <linux/init.h> > +#include <linux/slab.h> > +#include <linux/i2c.h> > +#include <linux/gpio.h> > +#include <linux/workqueue.h> > +#include <linux/irq.h> > +#include <linux/regmap.h> > +#include <linux/err.h> > +#include <linux/mfd/core.h> > +#include <linux/mfd/smsc.h> > +#include <linux/of_platform.h> > + > +static struct regmap_config smsc_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .max_register = SMSC_MAX_REGISTER - 1; > + .cache_type = REGCACHE_COMPRESSED, > +}; You can remove one extra tab here. > + > +static const struct of_device_id of_smsc_match[] = { > + { .compatible = "smsc,ece1099", }, > + { }, > +}; > + > +static int smsc_i2c_probe(struct i2c_client *i2c, > + const struct i2c_device_id *id) > +{ > + struct device_node *node = i2c->dev.of_node; > + struct smsc *smsc; > + int ret = 0; > + > + smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), > + GFP_KERNEL); > + You must check the return value here? > + smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); > + if (IS_ERR(smsc->regmap)) { > + ret = PTR_ERR(smsc->regmap); > + goto err; You can simply return from here right? > + } > + > + i2c_set_clientdata(i2c, smsc); > + smsc->dev = &i2c->dev; > + > +#ifdef CONFIG_OF > + of_property_read_u32(node, "clock", &smsc->clk); > +#endif > + > + regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); > + regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); > + regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); > + regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); > + You also want to check return value here. > + dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", > + devid, rev, (venid_h << 8) | venid_l); > + > + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); > + if (ret) > + goto err; > + > + if (node) > + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); > + of_xxx above is encapsulated in CONFIG_OF macro, same is not done here. > + return ret; > + This return is not required, as next instruction. Infact I would suggest you can simply return from each places above. Thanks, Vaibhav > +err: > + return ret; > +} > + > +static int smsc_i2c_remove(struct i2c_client *i2c) > +{ > + return 0; > +} > + > +static const struct i2c_device_id smsc_i2c_id[] = { > + { "smscece1099", 0}, > + {}, > +}; > +MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); > + > +static struct i2c_driver smsc_i2c_driver = { > + .driver = { > + .name = "smsc", > + .of_match_table = of_smsc_match, > + .owner = THIS_MODULE, > + }, > + .probe = smsc_i2c_probe, > + .remove = smsc_i2c_remove, > + .id_table = smsc_i2c_id, > +}; > + > +module_i2c_driver(smsc_i2c_driver); > + > +MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); > +MODULE_DESCRIPTION("SMSC chip multi-function driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/include/linux/mfd/smsc.h b/include/linux/mfd/smsc.h > new file mode 100644 > index 0000000..adfaec2 > --- /dev/null > +++ b/include/linux/mfd/smsc.h > @@ -0,0 +1,111 @@ > +/* > + * SMSC ECE1099 > + * > + * Copyright 2012 Texas Instruments Inc. > + * > + * Author: Sourav Poddar <sourav.poddar@ti.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + * > + */ > + > +#ifndef __LINUX_MFD_SMSC_H > +#define __LINUX_MFD_SMSC_H > + > +#include <linux/regmap.h> > + > +#define SMSC_ID_ECE1099 1 > +#define SMSC_NUM_CLIENTS 2 > + > +#define SMSC_BASE_ADDR 0x38 > +#define OMAP_GPIO_SMSC_IRQ 151 > + > +#define SMSC_MAXGPIO 32 > +#define SMSC_BANK(offs) ((offs) >> 3) > +#define SMSC_BIT(offs) (1u << ((offs) & 0x7)) > + > +struct smsc { > + struct device *dev; > + struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS]; > + struct regmap *regmap; > + int clk; > + /* Stored chip id */ > + int id; > +}; > + > +struct smsc_gpio; > +struct smsc_keypad; > + > +static inline int smsc_read(struct device *child, unsigned int reg, > + unsigned int *dest) > +{ > + struct smsc *smsc = dev_get_drvdata(child->parent); > + > + return regmap_read(smsc->regmap, reg, dest); > +} > + > +static inline int smsc_write(struct device *child, unsigned int reg, > + unsigned int value) > +{ > + struct smsc *smsc = dev_get_drvdata(child->parent); > + > + return regmap_write(smsc->regmap, reg, value); > +} > + > +/* Registers for SMSC */ > +#define SMSC_RESET 0xF5 > +#define SMSC_GRP_INT 0xF9 > +#define SMSC_CLK_CTRL 0xFA > +#define SMSC_WKUP_CTRL 0xFB > +#define SMSC_DEV_ID 0xFC > +#define SMSC_DEV_REV 0xFD > +#define SMSC_VEN_ID_L 0xFE > +#define SMSC_VEN_ID_H 0xFF > + > +#define SMSC_MAX_REG (SMSC_VEN_ID_H + 1) > + > +/* CLK VALUE */ > +#define SMSC_CLK_VALUE 0x13 > + > +/* Registers for function GPIO INPUT */ > +#define SMSC_GPIO_DATA_IN_START 0x00 > + > +/* Registers for function GPIO OUPUT */ > +#define SMSC_GPIO_DATA_OUT_START 0x05 > + > +/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/ > +#define SMSC_GPIO_INPUT_LOW 0x01 > +#define SMSC_GPIO_INPUT_RISING 0x09 > +#define SMSC_GPIO_INPUT_FALLING 0x11 > +#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19 > +#define SMSC_GPIO_OUTPUT_PP 0x21 > +#define SMSC_GPIO_OUTPUT_OP 0x31 > + > +#define GRP_INT_STAT 0xf9 > +#define SMSC_GPI_INT 0x0f > +#define SMSC_CFG_START 0x0A > + > +/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/ > +#define SMSC_GPIO_INT_STAT_START 0x32 > + > +/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/ > +#define SMSC_GPIO_INT_MASK_START 0x37 > + > +/* Registers for SMSC function KEYPAD*/ > +#define SMSC_KP_OUT 0x40 > +#define SMSC_KP_IN 0x41 > +#define SMSC_KP_INT_STAT 0x42 > +#define SMSC_KP_INT_MASK 0x43 > + > +/* Definitions for keypad */ > +#define SMSC_KP_KSO 0x70 > +#define SMSC_KP_KSI 0x51 > +#define SMSC_KSO_ALL_LOW 0x20 > +#define SMSC_KP_SET_LOW_PWR 0x0B > +#define SMSC_KP_SET_HIGH 0xFF > +#define SMSC_KSO_EVAL 0x00 > + > +#endif /* __LINUX_MFD_SMSC_H */ > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi, On Wed, Sep 5, 2012 at 11:23 PM, Vaibhav Hiremath <hvaibhav@ti.com> wrote: > > > On 9/5/2012 5:06 PM, Sourav Poddar wrote: >> smsc ece1099 is a keyboard scan or gpio expansion device. >> The patch create keypad and gpio expander child for this >> multi function smsc driver. >> >> Cc: Samuel Ortiz <sameo@linux.intel.com> >> Cc: Benoit Cousson <b-cousson@ti.com> >> Cc: Felipe Balbi <balbi@ti.com> >> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> >> Signed-off-by: Sourav Poddar <sourav.poddar@ti.com> >> --- >> Changes since v1: >> - Use Kconfig option correctly >> - Add regmap_config paramters >> - Modify formatting of logs for devid >> - Move read/write function to headed file as an inline >> function. >> Documentation/smsc_ece1099.txt | 56 ++++++++++++++++++++ >> drivers/mfd/Kconfig | 12 ++++ >> drivers/mfd/Makefile | 1 + >> drivers/mfd/smsc-ece1099.c | 110 +++++++++++++++++++++++++++++++++++++++ >> include/linux/mfd/smsc.h | 111 ++++++++++++++++++++++++++++++++++++++++ >> 5 files changed, 290 insertions(+), 0 deletions(-) >> create mode 100644 Documentation/smsc_ece1099.txt >> create mode 100644 drivers/mfd/smsc-ece1099.c >> create mode 100644 include/linux/mfd/smsc.h >> >> diff --git a/Documentation/smsc_ece1099.txt b/Documentation/smsc_ece1099.txt >> new file mode 100644 >> index 0000000..6b492e8 >> --- /dev/null >> +++ b/Documentation/smsc_ece1099.txt >> @@ -0,0 +1,56 @@ >> +What is smsc-ece1099? >> +---------------------- >> + >> +The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion >> +or GPIO Expansion device. The device supports a keyboard >> +scan matrix of 23x8. The device is connected to a Master >> +via the SMSC BC-Link interface or via the SMBus. >> +Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals >> +are multiplexed with GPIOs. >> + >> +Interrupt generation >> +-------------------- >> + >> +Interrupts can be generated by an edge detection on a GPIO >> +pin or an edge detection on one of the bus interface pins. >> +Interrupts can also be detected on the keyboard scan interface. >> +The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if >> +any bit in one of the Interrupt Status registers is 1 and >> +the corresponding Interrupt Mask bit is also 1. >> + >> +In order for software to determine which device is the source >> +of an interrupt, it should first read the Group Interrupt Status Register >> +to determine which Status register group is a source for the interrupt. >> +Software should read both the Status register and the associated Mask register, >> +then AND the two values together. Bits that are 1 in the result of the AND >> +are active interrupts. Software clears an interrupt by writing a 1 to the >> +corresponding bit in the Status register. >> + >> +Communication Protocol >> +---------------------- >> + >> +- SMbus slave Interface >> + The host processor communicates with the ECE1099 device >> + through a series of read/write registers via the SMBus >> + interface. SMBus is a serial communication protocol between >> + a computer host and its peripheral devices. The SMBus data >> + rate is 10KHz minimum to 400 KHz maximum >> + >> +- Slave Bus Interface >> + The ECE1099 device SMBus implementation is a subset of the >> + SMBus interface to the host. The device is a slave-only SMBus device. >> + The implementation in the device is a subset of SMBus since it >> + only supports four protocols. >> + >> + The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the >> + only valid SMBus protocols for the device. >> + >> +- BC-LinkTM Interface >> + The BC-Link is a proprietary bus that allows communication >> + between a Master device and a Companion device. The Master >> + device uses this serial bus to read and write registers >> + located on the Companion device. The bus comprises three signals, >> + BC_CLK, BC_DAT and BC_INT#. The Master device always provides the >> + clock, BC_CLK, and the Companion device is the source for an >> + independent asynchronous interrupt signal, BC_INT#. The ECE1099 >> + supports BC-Link speeds up to 24MHz. >> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig >> index d1facef..991ef15 100644 >> --- a/drivers/mfd/Kconfig >> +++ b/drivers/mfd/Kconfig >> @@ -385,6 +385,18 @@ config MFD_T7L66XB >> help >> Support for Toshiba Mobile IO Controller T7L66XB >> >> +config MFD_SMSC >> + bool "Support for the SMSC ECE1099 series chips" >> + depends on I2C=y >> + select MFD_CORE >> + select REGMAP_I2C >> + help >> + If you say yes here you get support for the >> + ece1099 chips from SMSC. >> + >> + To compile this driver as a module, choose M here: the >> + module will be called smsc. >> + >> config MFD_TC6387XB >> bool "Support Toshiba TC6387XB" >> depends on ARM && HAVE_CLK >> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile >> index 79dd22d..f587d91 100644 >> --- a/drivers/mfd/Makefile >> +++ b/drivers/mfd/Makefile >> @@ -77,6 +77,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o >> obj-$(CONFIG_MCP) += mcp-core.o >> obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o >> obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o >> +obj-$(CONFIG_MFD_SMSC) += smsc.o >> obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o >> >> ifeq ($(CONFIG_SA1100_ASSABET),y) >> diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c >> new file mode 100644 >> index 0000000..73a6cb7 >> --- /dev/null >> +++ b/drivers/mfd/smsc-ece1099.c >> @@ -0,0 +1,110 @@ >> +/* >> + * TI SMSC MFD Driver >> + * >> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com >> + * >> + * Author: Sourav Poddar <sourav.poddar@ti.com> >> + * >> + * This program is free software; you can redistribute it and/or modify it >> + * under the terms of the GNU General Public License as published by the >> + * Free Software Foundation; GPL v2. >> + * >> + */ >> + >> +#include <linux/module.h> >> +#include <linux/moduleparam.h> >> +#include <linux/init.h> >> +#include <linux/slab.h> >> +#include <linux/i2c.h> >> +#include <linux/gpio.h> >> +#include <linux/workqueue.h> >> +#include <linux/irq.h> >> +#include <linux/regmap.h> >> +#include <linux/err.h> >> +#include <linux/mfd/core.h> >> +#include <linux/mfd/smsc.h> >> +#include <linux/of_platform.h> >> + >> +static struct regmap_config smsc_regmap_config = { >> + .reg_bits = 8, >> + .val_bits = 8, >> + .max_register = SMSC_MAX_REGISTER - 1; >> + .cache_type = REGCACHE_COMPRESSED, >> +}; > > You can remove one extra tab here. > Ok. >> + >> +static const struct of_device_id of_smsc_match[] = { >> + { .compatible = "smsc,ece1099", }, >> + { }, >> +}; >> + >> +static int smsc_i2c_probe(struct i2c_client *i2c, >> + const struct i2c_device_id *id) >> +{ >> + struct device_node *node = i2c->dev.of_node; >> + struct smsc *smsc; >> + int ret = 0; >> + >> + smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), >> + GFP_KERNEL); >> + > > You must check the return value here? > Yes, will include the check. >> + smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); >> + if (IS_ERR(smsc->regmap)) { >> + ret = PTR_ERR(smsc->regmap); >> + goto err; > > You can simply return from here right? > hmmm, yes. >> + } >> + >> + i2c_set_clientdata(i2c, smsc); >> + smsc->dev = &i2c->dev; >> + >> +#ifdef CONFIG_OF >> + of_property_read_u32(node, "clock", &smsc->clk); >> +#endif >> + >> + regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); >> + regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); >> + regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); >> + regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); >> + > > You also want to check return value here. > I dont see any point checking for the above ret values. These values are read during runtime and some can be zero also. ? >> + dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", >> + devid, rev, (venid_h << 8) | venid_l); >> + >> + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); >> + if (ret) >> + goto err; >> + >> + if (node) >> + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); >> + > > of_xxx above is encapsulated in CONFIG_OF macro, same is not done here. > Will include. >> + return ret; >> + > > This return is not required, as next instruction. Infact I would suggest > you can simply return from each places above. > Ok. > Thanks, > Vaibhav >> +err: >> + return ret; >> +} >> + >> +static int smsc_i2c_remove(struct i2c_client *i2c) >> +{ >> + return 0; >> +} >> + >> +static const struct i2c_device_id smsc_i2c_id[] = { >> + { "smscece1099", 0}, >> + {}, >> +}; >> +MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); >> + >> +static struct i2c_driver smsc_i2c_driver = { >> + .driver = { >> + .name = "smsc", >> + .of_match_table = of_smsc_match, >> + .owner = THIS_MODULE, >> + }, >> + .probe = smsc_i2c_probe, >> + .remove = smsc_i2c_remove, >> + .id_table = smsc_i2c_id, >> +}; >> + >> +module_i2c_driver(smsc_i2c_driver); >> + >> +MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); >> +MODULE_DESCRIPTION("SMSC chip multi-function driver"); >> +MODULE_LICENSE("GPL v2"); >> diff --git a/include/linux/mfd/smsc.h b/include/linux/mfd/smsc.h >> new file mode 100644 >> index 0000000..adfaec2 >> --- /dev/null >> +++ b/include/linux/mfd/smsc.h >> @@ -0,0 +1,111 @@ >> +/* >> + * SMSC ECE1099 >> + * >> + * Copyright 2012 Texas Instruments Inc. >> + * >> + * Author: Sourav Poddar <sourav.poddar@ti.com> >> + * >> + * This program is free software; you can redistribute it and/or modify it >> + * under the terms of the GNU General Public License as published by the >> + * Free Software Foundation; either version 2 of the License, or (at your >> + * option) any later version. >> + * >> + */ >> + >> +#ifndef __LINUX_MFD_SMSC_H >> +#define __LINUX_MFD_SMSC_H >> + >> +#include <linux/regmap.h> >> + >> +#define SMSC_ID_ECE1099 1 >> +#define SMSC_NUM_CLIENTS 2 >> + >> +#define SMSC_BASE_ADDR 0x38 >> +#define OMAP_GPIO_SMSC_IRQ 151 >> + >> +#define SMSC_MAXGPIO 32 >> +#define SMSC_BANK(offs) ((offs) >> 3) >> +#define SMSC_BIT(offs) (1u << ((offs) & 0x7)) >> + >> +struct smsc { >> + struct device *dev; >> + struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS]; >> + struct regmap *regmap; >> + int clk; >> + /* Stored chip id */ >> + int id; >> +}; >> + >> +struct smsc_gpio; >> +struct smsc_keypad; >> + >> +static inline int smsc_read(struct device *child, unsigned int reg, >> + unsigned int *dest) >> +{ >> + struct smsc *smsc = dev_get_drvdata(child->parent); >> + >> + return regmap_read(smsc->regmap, reg, dest); >> +} >> + >> +static inline int smsc_write(struct device *child, unsigned int reg, >> + unsigned int value) >> +{ >> + struct smsc *smsc = dev_get_drvdata(child->parent); >> + >> + return regmap_write(smsc->regmap, reg, value); >> +} >> + >> +/* Registers for SMSC */ >> +#define SMSC_RESET 0xF5 >> +#define SMSC_GRP_INT 0xF9 >> +#define SMSC_CLK_CTRL 0xFA >> +#define SMSC_WKUP_CTRL 0xFB >> +#define SMSC_DEV_ID 0xFC >> +#define SMSC_DEV_REV 0xFD >> +#define SMSC_VEN_ID_L 0xFE >> +#define SMSC_VEN_ID_H 0xFF >> + >> +#define SMSC_MAX_REG (SMSC_VEN_ID_H + 1) >> + >> +/* CLK VALUE */ >> +#define SMSC_CLK_VALUE 0x13 >> + >> +/* Registers for function GPIO INPUT */ >> +#define SMSC_GPIO_DATA_IN_START 0x00 >> + >> +/* Registers for function GPIO OUPUT */ >> +#define SMSC_GPIO_DATA_OUT_START 0x05 >> + >> +/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/ >> +#define SMSC_GPIO_INPUT_LOW 0x01 >> +#define SMSC_GPIO_INPUT_RISING 0x09 >> +#define SMSC_GPIO_INPUT_FALLING 0x11 >> +#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19 >> +#define SMSC_GPIO_OUTPUT_PP 0x21 >> +#define SMSC_GPIO_OUTPUT_OP 0x31 >> + >> +#define GRP_INT_STAT 0xf9 >> +#define SMSC_GPI_INT 0x0f >> +#define SMSC_CFG_START 0x0A >> + >> +/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/ >> +#define SMSC_GPIO_INT_STAT_START 0x32 >> + >> +/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/ >> +#define SMSC_GPIO_INT_MASK_START 0x37 >> + >> +/* Registers for SMSC function KEYPAD*/ >> +#define SMSC_KP_OUT 0x40 >> +#define SMSC_KP_IN 0x41 >> +#define SMSC_KP_INT_STAT 0x42 >> +#define SMSC_KP_INT_MASK 0x43 >> + >> +/* Definitions for keypad */ >> +#define SMSC_KP_KSO 0x70 >> +#define SMSC_KP_KSI 0x51 >> +#define SMSC_KSO_ALL_LOW 0x20 >> +#define SMSC_KP_SET_LOW_PWR 0x0B >> +#define SMSC_KP_SET_HIGH 0xFF >> +#define SMSC_KSO_EVAL 0x00 >> + >> +#endif /* __LINUX_MFD_SMSC_H */ >> -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Sep 05, 2012 at 05:06:04PM +0530, Sourav Poddar wrote: > +static struct regmap_config smsc_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .max_register = SMSC_MAX_REGISTER - 1; That max_register setup looks very odd... > + .cache_type = REGCACHE_COMPRESSED, > +}; Are you sure the compressed type is sensible? It would normally only make sense with a large number of closely packed registers but this device has 8 bit register values. > +#ifdef CONFIG_OF > + of_property_read_u32(node, "clock", &smsc->clk); > +#endif > + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); > + if (ret) > + goto err; What happens on non-DT systems? > +static int smsc_i2c_remove(struct i2c_client *i2c) > +{ > + return 0; > +} Remove empty functions, though it's rather surprising that there's nothing at all to do here.. Normally an MFD would at least remove its children. -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Sep 05, 2012 at 05:06:04PM +0530, Sourav Poddar wrote: > +static struct regmap_config smsc_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .max_register = SMSC_MAX_REGISTER - 1; > + .cache_type = REGCACHE_COMPRESSED, > +}; That definition of max_register looks wrong - why are we subtracting 1 from a macro called MAX_REGISTER to get it? Indentation here is a bit odd too. > +static int smsc_i2c_remove(struct i2c_client *i2c) > +{ > + return 0; > +} Remove empty functions. -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi, On Tue, Sep 25, 2012 at 11:22 PM, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote: > On Wed, Sep 05, 2012 at 05:06:04PM +0530, Sourav Poddar wrote: > >> +static struct regmap_config smsc_regmap_config = { >> + .reg_bits = 8, >> + .val_bits = 8, >> + .max_register = SMSC_MAX_REGISTER - 1; >> + .cache_type = REGCACHE_COMPRESSED, >> +}; > > That definition of max_register looks wrong - why are we subtracting 1 > from a macro called MAX_REGISTER to get it? > Yes, my bad. Actually, I have define in .h file something like this.. #define SMSC_MAX_REG (SMSC_VEN_ID_H + 1) where SMSC_VEN_ID_H is the last register address which this chip supports. I think I should directly assign max_address to SMSC_VEN_ID_H. ? + + > Indentation here is a bit odd too. > Will rectify. >> +static int smsc_i2c_remove(struct i2c_client *i2c) >> +{ >> + return 0; >> +} > > Remove empty functions. Ok. -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/smsc_ece1099.txt b/Documentation/smsc_ece1099.txt new file mode 100644 index 0000000..6b492e8 --- /dev/null +++ b/Documentation/smsc_ece1099.txt @@ -0,0 +1,56 @@ +What is smsc-ece1099? +---------------------- + +The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion +or GPIO Expansion device. The device supports a keyboard +scan matrix of 23x8. The device is connected to a Master +via the SMSC BC-Link interface or via the SMBus. +Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals +are multiplexed with GPIOs. + +Interrupt generation +-------------------- + +Interrupts can be generated by an edge detection on a GPIO +pin or an edge detection on one of the bus interface pins. +Interrupts can also be detected on the keyboard scan interface. +The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if +any bit in one of the Interrupt Status registers is 1 and +the corresponding Interrupt Mask bit is also 1. + +In order for software to determine which device is the source +of an interrupt, it should first read the Group Interrupt Status Register +to determine which Status register group is a source for the interrupt. +Software should read both the Status register and the associated Mask register, +then AND the two values together. Bits that are 1 in the result of the AND +are active interrupts. Software clears an interrupt by writing a 1 to the +corresponding bit in the Status register. + +Communication Protocol +---------------------- + +- SMbus slave Interface + The host processor communicates with the ECE1099 device + through a series of read/write registers via the SMBus + interface. SMBus is a serial communication protocol between + a computer host and its peripheral devices. The SMBus data + rate is 10KHz minimum to 400 KHz maximum + +- Slave Bus Interface + The ECE1099 device SMBus implementation is a subset of the + SMBus interface to the host. The device is a slave-only SMBus device. + The implementation in the device is a subset of SMBus since it + only supports four protocols. + + The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the + only valid SMBus protocols for the device. + +- BC-LinkTM Interface + The BC-Link is a proprietary bus that allows communication + between a Master device and a Companion device. The Master + device uses this serial bus to read and write registers + located on the Companion device. The bus comprises three signals, + BC_CLK, BC_DAT and BC_INT#. The Master device always provides the + clock, BC_CLK, and the Companion device is the source for an + independent asynchronous interrupt signal, BC_INT#. The ECE1099 + supports BC-Link speeds up to 24MHz. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d1facef..991ef15 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -385,6 +385,18 @@ config MFD_T7L66XB help Support for Toshiba Mobile IO Controller T7L66XB +config MFD_SMSC + bool "Support for the SMSC ECE1099 series chips" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + help + If you say yes here you get support for the + ece1099 chips from SMSC. + + To compile this driver as a module, choose M here: the + module will be called smsc. + config MFD_TC6387XB bool "Support Toshiba TC6387XB" depends on ARM && HAVE_CLK diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 79dd22d..f587d91 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o +obj-$(CONFIG_MFD_SMSC) += smsc.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ifeq ($(CONFIG_SA1100_ASSABET),y) diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c new file mode 100644 index 0000000..73a6cb7 --- /dev/null +++ b/drivers/mfd/smsc-ece1099.c @@ -0,0 +1,110 @@ +/* + * TI SMSC MFD Driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Sourav Poddar <sourav.poddar@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; GPL v2. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/regmap.h> +#include <linux/err.h> +#include <linux/mfd/core.h> +#include <linux/mfd/smsc.h> +#include <linux/of_platform.h> + +static struct regmap_config smsc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = SMSC_MAX_REGISTER - 1; + .cache_type = REGCACHE_COMPRESSED, +}; + +static const struct of_device_id of_smsc_match[] = { + { .compatible = "smsc,ece1099", }, + { }, +}; + +static int smsc_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device_node *node = i2c->dev.of_node; + struct smsc *smsc; + int ret = 0; + + smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), + GFP_KERNEL); + + smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); + if (IS_ERR(smsc->regmap)) { + ret = PTR_ERR(smsc->regmap); + goto err; + } + + i2c_set_clientdata(i2c, smsc); + smsc->dev = &i2c->dev; + +#ifdef CONFIG_OF + of_property_read_u32(node, "clock", &smsc->clk); +#endif + + regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); + regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); + regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); + regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); + + dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", + devid, rev, (venid_h << 8) | venid_l); + + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); + if (ret) + goto err; + + if (node) + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); + + return ret; + +err: + return ret; +} + +static int smsc_i2c_remove(struct i2c_client *i2c) +{ + return 0; +} + +static const struct i2c_device_id smsc_i2c_id[] = { + { "smscece1099", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); + +static struct i2c_driver smsc_i2c_driver = { + .driver = { + .name = "smsc", + .of_match_table = of_smsc_match, + .owner = THIS_MODULE, + }, + .probe = smsc_i2c_probe, + .remove = smsc_i2c_remove, + .id_table = smsc_i2c_id, +}; + +module_i2c_driver(smsc_i2c_driver); + +MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); +MODULE_DESCRIPTION("SMSC chip multi-function driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/smsc.h b/include/linux/mfd/smsc.h new file mode 100644 index 0000000..adfaec2 --- /dev/null +++ b/include/linux/mfd/smsc.h @@ -0,0 +1,111 @@ +/* + * SMSC ECE1099 + * + * Copyright 2012 Texas Instruments Inc. + * + * Author: Sourav Poddar <sourav.poddar@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __LINUX_MFD_SMSC_H +#define __LINUX_MFD_SMSC_H + +#include <linux/regmap.h> + +#define SMSC_ID_ECE1099 1 +#define SMSC_NUM_CLIENTS 2 + +#define SMSC_BASE_ADDR 0x38 +#define OMAP_GPIO_SMSC_IRQ 151 + +#define SMSC_MAXGPIO 32 +#define SMSC_BANK(offs) ((offs) >> 3) +#define SMSC_BIT(offs) (1u << ((offs) & 0x7)) + +struct smsc { + struct device *dev; + struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS]; + struct regmap *regmap; + int clk; + /* Stored chip id */ + int id; +}; + +struct smsc_gpio; +struct smsc_keypad; + +static inline int smsc_read(struct device *child, unsigned int reg, + unsigned int *dest) +{ + struct smsc *smsc = dev_get_drvdata(child->parent); + + return regmap_read(smsc->regmap, reg, dest); +} + +static inline int smsc_write(struct device *child, unsigned int reg, + unsigned int value) +{ + struct smsc *smsc = dev_get_drvdata(child->parent); + + return regmap_write(smsc->regmap, reg, value); +} + +/* Registers for SMSC */ +#define SMSC_RESET 0xF5 +#define SMSC_GRP_INT 0xF9 +#define SMSC_CLK_CTRL 0xFA +#define SMSC_WKUP_CTRL 0xFB +#define SMSC_DEV_ID 0xFC +#define SMSC_DEV_REV 0xFD +#define SMSC_VEN_ID_L 0xFE +#define SMSC_VEN_ID_H 0xFF + +#define SMSC_MAX_REG (SMSC_VEN_ID_H + 1) + +/* CLK VALUE */ +#define SMSC_CLK_VALUE 0x13 + +/* Registers for function GPIO INPUT */ +#define SMSC_GPIO_DATA_IN_START 0x00 + +/* Registers for function GPIO OUPUT */ +#define SMSC_GPIO_DATA_OUT_START 0x05 + +/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/ +#define SMSC_GPIO_INPUT_LOW 0x01 +#define SMSC_GPIO_INPUT_RISING 0x09 +#define SMSC_GPIO_INPUT_FALLING 0x11 +#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19 +#define SMSC_GPIO_OUTPUT_PP 0x21 +#define SMSC_GPIO_OUTPUT_OP 0x31 + +#define GRP_INT_STAT 0xf9 +#define SMSC_GPI_INT 0x0f +#define SMSC_CFG_START 0x0A + +/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/ +#define SMSC_GPIO_INT_STAT_START 0x32 + +/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/ +#define SMSC_GPIO_INT_MASK_START 0x37 + +/* Registers for SMSC function KEYPAD*/ +#define SMSC_KP_OUT 0x40 +#define SMSC_KP_IN 0x41 +#define SMSC_KP_INT_STAT 0x42 +#define SMSC_KP_INT_MASK 0x43 + +/* Definitions for keypad */ +#define SMSC_KP_KSO 0x70 +#define SMSC_KP_KSI 0x51 +#define SMSC_KSO_ALL_LOW 0x20 +#define SMSC_KP_SET_LOW_PWR 0x0B +#define SMSC_KP_SET_HIGH 0xFF +#define SMSC_KSO_EVAL 0x00 + +#endif /* __LINUX_MFD_SMSC_H */
smsc ece1099 is a keyboard scan or gpio expansion device. The patch create keypad and gpio expander child for this multi function smsc driver. Cc: Samuel Ortiz <sameo@linux.intel.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Felipe Balbi <balbi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Sourav Poddar <sourav.poddar@ti.com> --- Changes since v1: - Use Kconfig option correctly - Add regmap_config paramters - Modify formatting of logs for devid - Move read/write function to headed file as an inline function. Documentation/smsc_ece1099.txt | 56 ++++++++++++++++++++ drivers/mfd/Kconfig | 12 ++++ drivers/mfd/Makefile | 1 + drivers/mfd/smsc-ece1099.c | 110 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/smsc.h | 111 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+), 0 deletions(-) create mode 100644 Documentation/smsc_ece1099.txt create mode 100644 drivers/mfd/smsc-ece1099.c create mode 100644 include/linux/mfd/smsc.h