* [PATCH v2 0/2] Add stmpe mfd @ 2012-09-03 11:03 Steffen Trumtrar 2012-09-03 11:03 ` [PATCH v2 1/2] mfd: add stmpe-i2c driver Steffen Trumtrar 2012-09-03 11:03 ` [PATCH v2 2/2] gpio: add driver for stmpe io-expander Steffen Trumtrar 0 siblings, 2 replies; 7+ messages in thread From: Steffen Trumtrar @ 2012-09-03 11:03 UTC (permalink / raw) To: barebox; +Cc: Steffen Trumtrar Hi, this adds support for a stmpe1601 mfd connected via i2c. This was only tested with the gpiolib support from the previous patch-series "ARM i.MX: add gpiolib support". With v2 I added the dependency on gpiolib in the Kconfig file and removed the hardcoded gpiobase by a platformdata-provided or dynamic gpiobase. Regards, Steffen Steffen Trumtrar (2): mfd: add stmpe-i2c driver gpio: add driver for stmpe io-expander drivers/Kconfig | 1 + drivers/gpio/Kconfig | 9 +++ drivers/gpio/Makefile | 2 + drivers/gpio/gpio-stmpe.c | 162 +++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/Kconfig | 4 ++ drivers/mfd/Makefile | 1 + drivers/mfd/stmpe-i2c.c | 166 +++++++++++++++++++++++++++++++++++++++++++++ include/mfd/stmpe-i2c.h | 56 +++++++++++++++ 8 files changed, 401 insertions(+) create mode 100644 drivers/gpio/Kconfig create mode 100644 drivers/gpio/Makefile create mode 100644 drivers/gpio/gpio-stmpe.c create mode 100644 drivers/mfd/stmpe-i2c.c create mode 100644 include/mfd/stmpe-i2c.h -- 1.7.10.4 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] mfd: add stmpe-i2c driver 2012-09-03 11:03 [PATCH v2 0/2] Add stmpe mfd Steffen Trumtrar @ 2012-09-03 11:03 ` Steffen Trumtrar 2012-09-04 8:11 ` Sascha Hauer 2012-09-04 8:18 ` Marc Kleine-Budde 2012-09-03 11:03 ` [PATCH v2 2/2] gpio: add driver for stmpe io-expander Steffen Trumtrar 1 sibling, 2 replies; 7+ messages in thread From: Steffen Trumtrar @ 2012-09-03 11:03 UTC (permalink / raw) To: barebox; +Cc: Steffen Trumtrar The stmpe mfds can be connected via i2c and spi. This driver provides the basic infrastructure for the i2c kind. It can be added as a normal i2c-device in the board code. To enable functions a platform_data struct has to be provided, that describes what parts of the chip are to be used. Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> --- drivers/mfd/Kconfig | 4 ++ drivers/mfd/Makefile | 1 + drivers/mfd/stmpe-i2c.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++ include/mfd/stmpe-i2c.h | 56 ++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 drivers/mfd/stmpe-i2c.c create mode 100644 include/mfd/stmpe-i2c.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index af67935..20eef86 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -33,4 +33,8 @@ config I2C_TWL6030 select I2C_TWLCORE bool "TWL6030 driver" +config I2C_STMPE + depends on I2C + bool "STMPE-i2c driver" + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index e11223b..792ae2d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_I2C_LP3972) += lp3972.o obj-$(CONFIG_I2C_TWLCORE) += twl-core.o obj-$(CONFIG_I2C_TWL4030) += twl4030.o obj-$(CONFIG_I2C_TWL6030) += twl6030.o +obj-$(CONFIG_I2C_STMPE) += stmpe-i2c.o diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c new file mode 100644 index 0000000..a0cfa75 --- /dev/null +++ b/drivers/mfd/stmpe-i2c.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012 Pengutronix + * Steffen Trumtrar <s.trumtrar@pengutronix.de> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <xfuncs.h> +#include <errno.h> + +#include <i2c/i2c.h> +#include <mfd/stmpe-i2c.h> + +#define DRIVERNAME "stmpe-i2c" + +#define to_stmpe(a) container_of(a, struct stmpe, cdev) + +static struct stmpe *stmpe_dev; + +struct stmpe *stmpe_get(void) +{ + if (!stmpe_dev) + return NULL; + + return stmpe_dev; +} +EXPORT_SYMBOL(stmpe_get); + +int stmpe_reg_read(struct stmpe *stmpe, u32 reg, u8 *val) +{ + int ret; + + ret = i2c_read_reg(stmpe->client, reg, val, 1); + + return ret == 1 ? 0 : ret; +} +EXPORT_SYMBOL(stmpe_reg_read) + +int stmpe_reg_write(struct stmpe *stmpe, u32 reg, u8 val) +{ + int ret; + + ret = i2c_write_reg(stmpe->client, reg, &val, 1); + + return ret == 1 ? 0 : ret; +} +EXPORT_SYMBOL(stmpe_reg_write) + +int stmpe_set_bits(struct stmpe *stmpe, u32 reg, u8 mask, u8 val) +{ + u8 tmp; + int err; + + err = stmpe_reg_read(stmpe, reg, &tmp); + tmp = (tmp & ~mask) | val; + + if (!err) + err = stmpe_reg_write(stmpe, reg, tmp); + + return err; +} +EXPORT_SYMBOL(stmpe_set_bits); + +static ssize_t stmpe_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags) +{ + struct stmpe *stmpe = to_stmpe(cdev); + u8 *buf = _buf; + size_t i = count; + int err; + + while (i) { + err = stmpe_reg_read(stmpe, offset, buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static ssize_t stmpe_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags) +{ + struct stmpe *stmpe = to_stmpe(cdev); + const u8 *buf = _buf; + size_t i = count; + int err; + + while (i) { + err = stmpe_reg_write(stmpe, offset, *buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static struct file_operations stmpe_fops = { + .lseek = dev_lseek_default, + .read = stmpe_read, + .write = stmpe_write, +}; + +static struct stmpe_client_info i2c_ci = { + .read_reg = stmpe_reg_read, + .write_reg = stmpe_reg_write, +}; + +static int stmpe_probe(struct device_d *dev) +{ + struct stmpe_platform_data *pdata = dev->platform_data; + + if (!pdata) { + dev_dbg(dev, "no platform data\n"); + return -ENODEV; + } + + if (stmpe_dev) + return -EBUSY; + + stmpe_dev = xzalloc(sizeof(struct stmpe)); + stmpe_dev->cdev.name = DRIVERNAME; + stmpe_dev->client = to_i2c_client(dev); + stmpe_dev->cdev.size = 191; /* 191 known registers */ + stmpe_dev->cdev.dev = dev; + stmpe_dev->cdev.ops = &stmpe_fops; + stmpe_dev->pdata = pdata; + dev->priv = stmpe_dev; + i2c_ci.stmpe = stmpe_dev; + + if (pdata->blocks &= STMPE_BLOCK_GPIO) + add_generic_device("stmpe-gpio", 0, NULL, (void __iomem *)pdata->base, 0x10, IORESOURCE_MEM, &i2c_ci); + + devfs_create(&stmpe_dev->cdev); + + return 0; +} + +static struct driver_d stmpe_driver = { + .name = DRIVERNAME, + .probe = stmpe_probe, +}; + +static int stmpe_init(void) +{ + register_driver(&stmpe_driver); + return 0; +} + +device_initcall(stmpe_init); diff --git a/include/mfd/stmpe-i2c.h b/include/mfd/stmpe-i2c.h new file mode 100644 index 0000000..c36aed9 --- /dev/null +++ b/include/mfd/stmpe-i2c.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 Pengutronix + * Steffen Trumtrar <s.trumtrar@pengutronix.de> + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_ARCH_STMPE_H +#define __ASM_ARCH_STMPE_H + +enum stmpe_revision { + STMPE610, + STMPE801, + STMPE811, + STMPE1601, + STMPE2401, + STMPE2403, + STMPE_NBR_PARTS +}; + +enum stmpe_blocks { + STMPE_BLOCK_GPIO = 1 << 0, + STMPE_BLOCK_KEYPAD = 1 << 1, + STMPE_BLOCK_TOUCHSCREEN = 1 << 2, + STMPE_BLOCK_ADC = 1 << 3, + STMPE_BLOCK_PWM = 1 << 4, + STMPE_BLOCK_ROTATOR = 1 << 5, +}; + +struct stmpe_platform_data { + enum stmpe_revision revision; + enum stmpe_blocks blocks; + void __iomem *base; + int gpio_base; +}; + +struct stmpe { + struct cdev cdev; + struct i2c_client *client; + struct stmpe_platform_data *pdata; +}; + +struct stmpe_client_info { + struct stmpe *stmpe; + int (*read_reg)(struct stmpe *stmpe, u32 reg, u8 *val); + int (*write_reg)(struct stmpe *stmpe, u32 reg, u8 val); +}; + +extern struct stmpe *stmpe_get(void); + +extern int stmpe_reg_read(struct stmpe *priv, u32 reg, u8 *val); +extern int stmpe_reg_write(struct stmpe *priv, u32 reg, u8 val); +extern int stmpe_set_bits(struct stmpe *priv, u32 reg, u8 mask, u8 val); + +#endif /* __ASM_ARCH_STMPE_H */ -- 1.7.10.4 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] mfd: add stmpe-i2c driver 2012-09-03 11:03 ` [PATCH v2 1/2] mfd: add stmpe-i2c driver Steffen Trumtrar @ 2012-09-04 8:11 ` Sascha Hauer 2012-09-04 8:18 ` Marc Kleine-Budde 1 sibling, 0 replies; 7+ messages in thread From: Sascha Hauer @ 2012-09-04 8:11 UTC (permalink / raw) To: Steffen Trumtrar; +Cc: barebox On Mon, Sep 03, 2012 at 01:03:46PM +0200, Steffen Trumtrar wrote: > The stmpe mfds can be connected via i2c and spi. This driver provides the basic > infrastructure for the i2c kind. It can be added as a normal i2c-device in the > board code. To enable functions a platform_data struct has to be provided, that > describes what parts of the chip are to be used. > > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> > + > +struct stmpe *stmpe_get(void) > +{ > + if (!stmpe_dev) > + return NULL; > + > + return stmpe_dev; > +} > +EXPORT_SYMBOL(stmpe_get); For the pmic devices the assumption that there is only one in the system is not nice, but reasonable. For this driver it is an unnecessary limitation. How about this: add a 'static struct stmpe stmpe_dev' just like you did, but instead of returning -EBUSY for the second one, do if (!stmpe_dev) stmpe_dev = newdev; This way the at least the gpio support works for multiple instances. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] mfd: add stmpe-i2c driver 2012-09-03 11:03 ` [PATCH v2 1/2] mfd: add stmpe-i2c driver Steffen Trumtrar 2012-09-04 8:11 ` Sascha Hauer @ 2012-09-04 8:18 ` Marc Kleine-Budde 1 sibling, 0 replies; 7+ messages in thread From: Marc Kleine-Budde @ 2012-09-04 8:18 UTC (permalink / raw) To: Steffen Trumtrar; +Cc: barebox [-- Attachment #1.1: Type: text/plain, Size: 7854 bytes --] On 09/03/2012 01:03 PM, Steffen Trumtrar wrote: > The stmpe mfds can be connected via i2c and spi. This driver provides the basic > infrastructure for the i2c kind. It can be added as a normal i2c-device in the > board code. To enable functions a platform_data struct has to be provided, that > describes what parts of the chip are to be used. > > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> > --- > drivers/mfd/Kconfig | 4 ++ > drivers/mfd/Makefile | 1 + > drivers/mfd/stmpe-i2c.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++ > include/mfd/stmpe-i2c.h | 56 ++++++++++++++++ > 4 files changed, 227 insertions(+) > create mode 100644 drivers/mfd/stmpe-i2c.c > create mode 100644 include/mfd/stmpe-i2c.h > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index af67935..20eef86 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -33,4 +33,8 @@ config I2C_TWL6030 > select I2C_TWLCORE > bool "TWL6030 driver" > > +config I2C_STMPE > + depends on I2C > + bool "STMPE-i2c driver" > + > endmenu > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > index e11223b..792ae2d 100644 > --- a/drivers/mfd/Makefile > +++ b/drivers/mfd/Makefile > @@ -6,3 +6,4 @@ obj-$(CONFIG_I2C_LP3972) += lp3972.o > obj-$(CONFIG_I2C_TWLCORE) += twl-core.o > obj-$(CONFIG_I2C_TWL4030) += twl4030.o > obj-$(CONFIG_I2C_TWL6030) += twl6030.o > +obj-$(CONFIG_I2C_STMPE) += stmpe-i2c.o > diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c > new file mode 100644 > index 0000000..a0cfa75 > --- /dev/null > +++ b/drivers/mfd/stmpe-i2c.c > @@ -0,0 +1,166 @@ > +/* > + * Copyright (C) 2012 Pengutronix > + * Steffen Trumtrar <s.trumtrar@pengutronix.de> > + * > + * 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. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <common.h> > +#include <init.h> > +#include <driver.h> > +#include <xfuncs.h> > +#include <errno.h> > + > +#include <i2c/i2c.h> > +#include <mfd/stmpe-i2c.h> > + > +#define DRIVERNAME "stmpe-i2c" > + > +#define to_stmpe(a) container_of(a, struct stmpe, cdev) > + > +static struct stmpe *stmpe_dev; > + > +struct stmpe *stmpe_get(void) > +{ > + if (!stmpe_dev) > + return NULL; nitpick, you can remove the above return :) > + > + return stmpe_dev; > +} > +EXPORT_SYMBOL(stmpe_get); > + > +int stmpe_reg_read(struct stmpe *stmpe, u32 reg, u8 *val) > +{ > + int ret; > + > + ret = i2c_read_reg(stmpe->client, reg, val, 1); > + > + return ret == 1 ? 0 : ret; > +} > +EXPORT_SYMBOL(stmpe_reg_read) > + > +int stmpe_reg_write(struct stmpe *stmpe, u32 reg, u8 val) > +{ > + int ret; > + > + ret = i2c_write_reg(stmpe->client, reg, &val, 1); > + > + return ret == 1 ? 0 : ret; > +} > +EXPORT_SYMBOL(stmpe_reg_write) > + > +int stmpe_set_bits(struct stmpe *stmpe, u32 reg, u8 mask, u8 val) > +{ > + u8 tmp; > + int err; > + > + err = stmpe_reg_read(stmpe, reg, &tmp); > + tmp = (tmp & ~mask) | val; > + > + if (!err) > + err = stmpe_reg_write(stmpe, reg, tmp); > + > + return err; > +} > +EXPORT_SYMBOL(stmpe_set_bits); > + > +static ssize_t stmpe_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags) > +{ > + struct stmpe *stmpe = to_stmpe(cdev); > + u8 *buf = _buf; > + size_t i = count; > + int err; > + > + while (i) { > + err = stmpe_reg_read(stmpe, offset, buf); > + if (err) > + return (ssize_t)err; > + buf++; > + i--; > + offset++; > + } > + > + return count; > +} > + > +static ssize_t stmpe_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags) > +{ > + struct stmpe *stmpe = to_stmpe(cdev); > + const u8 *buf = _buf; > + size_t i = count; > + int err; > + > + while (i) { > + err = stmpe_reg_write(stmpe, offset, *buf); > + if (err) > + return (ssize_t)err; > + buf++; > + i--; > + offset++; > + } > + > + return count; > +} > + > +static struct file_operations stmpe_fops = { > + .lseek = dev_lseek_default, > + .read = stmpe_read, > + .write = stmpe_write, > +}; > + > +static struct stmpe_client_info i2c_ci = { > + .read_reg = stmpe_reg_read, > + .write_reg = stmpe_reg_write, > +}; > + > +static int stmpe_probe(struct device_d *dev) > +{ > + struct stmpe_platform_data *pdata = dev->platform_data; > + > + if (!pdata) { > + dev_dbg(dev, "no platform data\n"); > + return -ENODEV; > + } > + > + if (stmpe_dev) > + return -EBUSY; > + > + stmpe_dev = xzalloc(sizeof(struct stmpe)); > + stmpe_dev->cdev.name = DRIVERNAME; > + stmpe_dev->client = to_i2c_client(dev); > + stmpe_dev->cdev.size = 191; /* 191 known registers */ > + stmpe_dev->cdev.dev = dev; > + stmpe_dev->cdev.ops = &stmpe_fops; > + stmpe_dev->pdata = pdata; > + dev->priv = stmpe_dev; > + i2c_ci.stmpe = stmpe_dev; > + > + if (pdata->blocks &= STMPE_BLOCK_GPIO) > + add_generic_device("stmpe-gpio", 0, NULL, (void __iomem *)pdata->base, 0x10, IORESOURCE_MEM, &i2c_ci); ^^^^^^^^^^^^^^ it's already void __iomem *, isn't it? > + > + devfs_create(&stmpe_dev->cdev); > + > + return 0; > +} > + > +static struct driver_d stmpe_driver = { > + .name = DRIVERNAME, > + .probe = stmpe_probe, > +}; > + > +static int stmpe_init(void) > +{ > + register_driver(&stmpe_driver); > + return 0; > +} > + > +device_initcall(stmpe_init); > diff --git a/include/mfd/stmpe-i2c.h b/include/mfd/stmpe-i2c.h > new file mode 100644 > index 0000000..c36aed9 > --- /dev/null > +++ b/include/mfd/stmpe-i2c.h > @@ -0,0 +1,56 @@ > +/* > + * Copyright (C) 2012 Pengutronix > + * Steffen Trumtrar <s.trumtrar@pengutronix.de> > + * > + * This file is released under the GPLv2 > + * > + */ > + > +#ifndef __ASM_ARCH_STMPE_H > +#define __ASM_ARCH_STMPE_H > + > +enum stmpe_revision { > + STMPE610, > + STMPE801, > + STMPE811, > + STMPE1601, > + STMPE2401, > + STMPE2403, > + STMPE_NBR_PARTS > +}; > + > +enum stmpe_blocks { > + STMPE_BLOCK_GPIO = 1 << 0, > + STMPE_BLOCK_KEYPAD = 1 << 1, > + STMPE_BLOCK_TOUCHSCREEN = 1 << 2, > + STMPE_BLOCK_ADC = 1 << 3, > + STMPE_BLOCK_PWM = 1 << 4, > + STMPE_BLOCK_ROTATOR = 1 << 5, > +}; > + > +struct stmpe_platform_data { > + enum stmpe_revision revision; > + enum stmpe_blocks blocks; > + void __iomem *base; > + int gpio_base; > +}; > + > +struct stmpe { > + struct cdev cdev; > + struct i2c_client *client; > + struct stmpe_platform_data *pdata; > +}; > + > +struct stmpe_client_info { > + struct stmpe *stmpe; > + int (*read_reg)(struct stmpe *stmpe, u32 reg, u8 *val); > + int (*write_reg)(struct stmpe *stmpe, u32 reg, u8 val); > +}; > + > +extern struct stmpe *stmpe_get(void); > + > +extern int stmpe_reg_read(struct stmpe *priv, u32 reg, u8 *val); > +extern int stmpe_reg_write(struct stmpe *priv, u32 reg, u8 val); > +extern int stmpe_set_bits(struct stmpe *priv, u32 reg, u8 mask, u8 val); > + > +#endif /* __ASM_ARCH_STMPE_H */ > Marc -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de | [-- Attachment #1.2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 259 bytes --] [-- Attachment #2: Type: text/plain, Size: 149 bytes --] _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] gpio: add driver for stmpe io-expander 2012-09-03 11:03 [PATCH v2 0/2] Add stmpe mfd Steffen Trumtrar 2012-09-03 11:03 ` [PATCH v2 1/2] mfd: add stmpe-i2c driver Steffen Trumtrar @ 2012-09-03 11:03 ` Steffen Trumtrar 2012-09-04 8:13 ` Sascha Hauer 2012-09-04 8:29 ` Marc Kleine-Budde 1 sibling, 2 replies; 7+ messages in thread From: Steffen Trumtrar @ 2012-09-03 11:03 UTC (permalink / raw) To: barebox; +Cc: Steffen Trumtrar Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> --- drivers/Kconfig | 1 + drivers/gpio/Kconfig | 9 +++ drivers/gpio/Makefile | 2 + drivers/gpio/gpio-stmpe.c | 162 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 drivers/gpio/Kconfig create mode 100644 drivers/gpio/Makefile create mode 100644 drivers/gpio/gpio-stmpe.c diff --git a/drivers/Kconfig b/drivers/Kconfig index 883b0e7..adf8fcd 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -18,5 +18,6 @@ source "drivers/input/Kconfig" source "drivers/watchdog/Kconfig" source "drivers/pwm/Kconfig" source "drivers/dma/Kconfig" +source "drivers/gpio/Kconfig" endmenu diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig new file mode 100644 index 0000000..acfd4ef --- /dev/null +++ b/drivers/gpio/Kconfig @@ -0,0 +1,9 @@ +menu "GPIO " + +config STMPE_GPIO + depends on I2C + depends on GPIOLIB + select I2C_STMPE + bool "STMPE GPIO Expander" + +endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile new file mode 100644 index 0000000..da1bc21 --- /dev/null +++ b/drivers/gpio/Makefile @@ -0,0 +1,2 @@ +obj-y += gpio.o +obj-$(CONFIG_STMPE_GPIO) += gpio-stmpe.o diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c new file mode 100644 index 0000000..74547d9 --- /dev/null +++ b/drivers/gpio/gpio-stmpe.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2012 Pengutronix + * Steffen Trumtrar <s.trumtrar@pengutronix.de> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <errno.h> +#include <io.h> +#include <gpio.h> +#include <init.h> +#include <mfd/stmpe-i2c.h> + +#define GPIO_BASE 0x80 +#define GPIO_SET (GPIO_BASE + 0x02) +#define GPIO_CLR (GPIO_BASE + 0x04) +#define GPIO_MP (GPIO_BASE + 0x06) +#define GPIO_SET_DIR (GPIO_BASE + 0x08) +#define GPIO_ED (GPIO_BASE + 0x0a) +#define GPIO_RE (GPIO_BASE + 0x0c) +#define GPIO_FE (GPIO_BASE + 0x0e) +#define GPIO_PULL_UP (GPIO_BASE + 0x10) +#define GPIO_AF (GPIO_BASE + 0x12) +#define GPIO_LT (GPIO_BASE + 0x16) + +#define OFFSET(gpio) (0xff & (1 << (gpio)) ? 1 : 0) + +extern void __iomem *stmpe_gpio_base[]; +extern int stmpe_gpio_count; + +struct stmpe_gpio_chip { + void __iomem *base; + struct gpio_chip chip; + void *ci; +}; + +static void stmpe_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; + int ret; + u8 val; + + ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val); + + val |= 1 << (gpio % 8); + + if (value) + ret = ci->write_reg(ci->stmpe, GPIO_SET + OFFSET(gpio), val); + else + ret = ci->write_reg(ci->stmpe, GPIO_CLR + OFFSET(gpio), val); + + if (ret) + dev_err(chip->dev, "write failed!\n"); +} + +static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; + int ret; + u8 val; + + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); + val &= ~(1 << (gpio % 8)); + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); + + if (ret) + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); + + return 0; +} + +static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; + int ret; + u8 val; + + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); + val |= 1 << (gpio % 8); + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); + + stmpe_gpio_set_value(chip, gpio, value); + + if (ret) + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); + + return 0; +} + +static int stmpe_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; + u8 val; + int ret; + + ret = ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val); + + if (ret) + dev_err(chip->dev, "read failed\n"); + + return val & (1 << (gpio % 8)) ? 1 : 0; +} + +static struct gpio_ops stmpe_gpio_ops = { + .direction_input = stmpe_gpio_direction_input, + .direction_output = stmpe_gpio_direction_output, + .get = stmpe_gpio_get_value, + .set = stmpe_gpio_set_value, +}; + +static int stmpe_gpio_probe(struct device_d *dev) +{ + struct stmpe_gpio_chip *stmpegpio; + struct stmpe_client_info *ci; + + stmpegpio = xzalloc(sizeof(*stmpegpio)); + + stmpegpio->base = dev_request_mem_region(dev, 0); + stmpegpio->chip.ops = &stmpe_gpio_ops; + stmpegpio->ci = dev->platform_data; + + ci = (struct stmpe_client_info *)stmpegpio->ci; + + if (ci->stmpe->pdata->gpio_base) + stmpegpio->chip.base = ci->stmpe->pdata->gpio_base; + else + stmpegpio->chip.base = -1; + + stmpegpio->chip.ngpio = 16; + stmpegpio->chip.dev = dev; + + gpiochip_add(&stmpegpio->chip); + + dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base); + return 0; +} + +static struct driver_d stmpe_gpio_driver = { + .name = "stmpe-gpio", + .probe = stmpe_gpio_probe, +}; + +static int stmpe_gpio_add(void) +{ + register_driver(&stmpe_gpio_driver); + return 0; +} +coredevice_initcall(stmpe_gpio_add); -- 1.7.10.4 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] gpio: add driver for stmpe io-expander 2012-09-03 11:03 ` [PATCH v2 2/2] gpio: add driver for stmpe io-expander Steffen Trumtrar @ 2012-09-04 8:13 ` Sascha Hauer 2012-09-04 8:29 ` Marc Kleine-Budde 1 sibling, 0 replies; 7+ messages in thread From: Sascha Hauer @ 2012-09-04 8:13 UTC (permalink / raw) To: Steffen Trumtrar; +Cc: barebox On Mon, Sep 03, 2012 at 01:03:47PM +0200, Steffen Trumtrar wrote: > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> > --- > +static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + int ret; > + u8 val; > + > + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); > + val &= ~(1 << (gpio % 8)); > + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); > + > + if (ret) > + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); > + > + return 0; Please propagate the error value. > +} > + > +static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + int ret; > + u8 val; > + > + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); > + val |= 1 << (gpio % 8); > + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); > + > + stmpe_gpio_set_value(chip, gpio, value); > + > + if (ret) > + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); > + > + return 0; ditto > + > +static int stmpe_gpio_probe(struct device_d *dev) > +{ > + struct stmpe_gpio_chip *stmpegpio; > + struct stmpe_client_info *ci; > + > + stmpegpio = xzalloc(sizeof(*stmpegpio)); > + > + stmpegpio->base = dev_request_mem_region(dev, 0); > + stmpegpio->chip.ops = &stmpe_gpio_ops; > + stmpegpio->ci = dev->platform_data; > + > + ci = (struct stmpe_client_info *)stmpegpio->ci; > + > + if (ci->stmpe->pdata->gpio_base) > + stmpegpio->chip.base = ci->stmpe->pdata->gpio_base; > + else > + stmpegpio->chip.base = -1; > + > + stmpegpio->chip.ngpio = 16; > + stmpegpio->chip.dev = dev; > + > + gpiochip_add(&stmpegpio->chip); It's worth checking the return value of gpiochip_add. It could indicate that the selected chip.base is busy. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] gpio: add driver for stmpe io-expander 2012-09-03 11:03 ` [PATCH v2 2/2] gpio: add driver for stmpe io-expander Steffen Trumtrar 2012-09-04 8:13 ` Sascha Hauer @ 2012-09-04 8:29 ` Marc Kleine-Budde 1 sibling, 0 replies; 7+ messages in thread From: Marc Kleine-Budde @ 2012-09-04 8:29 UTC (permalink / raw) To: Steffen Trumtrar; +Cc: barebox [-- Attachment #1.1: Type: text/plain, Size: 7225 bytes --] On 09/03/2012 01:03 PM, Steffen Trumtrar wrote: > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> > --- > drivers/Kconfig | 1 + > drivers/gpio/Kconfig | 9 +++ > drivers/gpio/Makefile | 2 + > drivers/gpio/gpio-stmpe.c | 162 +++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 174 insertions(+) > create mode 100644 drivers/gpio/Kconfig > create mode 100644 drivers/gpio/Makefile > create mode 100644 drivers/gpio/gpio-stmpe.c > > diff --git a/drivers/Kconfig b/drivers/Kconfig > index 883b0e7..adf8fcd 100644 > --- a/drivers/Kconfig > +++ b/drivers/Kconfig > @@ -18,5 +18,6 @@ source "drivers/input/Kconfig" > source "drivers/watchdog/Kconfig" > source "drivers/pwm/Kconfig" > source "drivers/dma/Kconfig" > +source "drivers/gpio/Kconfig" > > endmenu > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > new file mode 100644 > index 0000000..acfd4ef > --- /dev/null > +++ b/drivers/gpio/Kconfig > @@ -0,0 +1,9 @@ > +menu "GPIO " > + > +config STMPE_GPIO > + depends on I2C > + depends on GPIOLIB > + select I2C_STMPE > + bool "STMPE GPIO Expander" > + > +endmenu > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > new file mode 100644 > index 0000000..da1bc21 > --- /dev/null > +++ b/drivers/gpio/Makefile > @@ -0,0 +1,2 @@ > +obj-y += gpio.o > +obj-$(CONFIG_STMPE_GPIO) += gpio-stmpe.o > diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c > new file mode 100644 > index 0000000..74547d9 > --- /dev/null > +++ b/drivers/gpio/gpio-stmpe.c > @@ -0,0 +1,162 @@ > +/* > + * Copyright (C) 2012 Pengutronix > + * Steffen Trumtrar <s.trumtrar@pengutronix.de> > + * > + * 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. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <common.h> > +#include <errno.h> > +#include <io.h> > +#include <gpio.h> > +#include <init.h> > +#include <mfd/stmpe-i2c.h> > + > +#define GPIO_BASE 0x80 > +#define GPIO_SET (GPIO_BASE + 0x02) > +#define GPIO_CLR (GPIO_BASE + 0x04) > +#define GPIO_MP (GPIO_BASE + 0x06) > +#define GPIO_SET_DIR (GPIO_BASE + 0x08) > +#define GPIO_ED (GPIO_BASE + 0x0a) > +#define GPIO_RE (GPIO_BASE + 0x0c) > +#define GPIO_FE (GPIO_BASE + 0x0e) > +#define GPIO_PULL_UP (GPIO_BASE + 0x10) > +#define GPIO_AF (GPIO_BASE + 0x12) > +#define GPIO_LT (GPIO_BASE + 0x16) > + > +#define OFFSET(gpio) (0xff & (1 << (gpio)) ? 1 : 0) > + > +extern void __iomem *stmpe_gpio_base[]; > +extern int stmpe_gpio_count; Are these two used? > + > +struct stmpe_gpio_chip { > + void __iomem *base; ^^^^^^^^^^^^^^^^^^ Where is it used? An i2c device doesn't have iomem? > + struct gpio_chip chip; > + void *ci; why is this a void, not struct stmpe_client_info * > +}; > + > +static void stmpe_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + int ret; > + u8 val; > + > + ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val); > + > + val |= 1 << (gpio % 8); > + > + if (value) > + ret = ci->write_reg(ci->stmpe, GPIO_SET + OFFSET(gpio), val); > + else > + ret = ci->write_reg(ci->stmpe, GPIO_CLR + OFFSET(gpio), val); > + > + if (ret) > + dev_err(chip->dev, "write failed!\n"); > +} > + > +static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + int ret; > + u8 val; > + > + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); > + val &= ~(1 << (gpio % 8)); > + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); > + > + if (ret) > + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); > + > + return 0; > +} > + > +static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + int ret; > + u8 val; > + > + ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val); > + val |= 1 << (gpio % 8); > + ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val); > + > + stmpe_gpio_set_value(chip, gpio, value); > + > + if (ret) > + dev_err(chip->dev, "couldn't change direction. Write failed!\n"); > + > + return 0; > +} > + > +static int stmpe_gpio_get_value(struct gpio_chip *chip, unsigned gpio) > +{ > + struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip); > + struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci; > + u8 val; > + int ret; > + > + ret = ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val); > + > + if (ret) > + dev_err(chip->dev, "read failed\n"); > + > + return val & (1 << (gpio % 8)) ? 1 : 0; > +} > + > +static struct gpio_ops stmpe_gpio_ops = { > + .direction_input = stmpe_gpio_direction_input, > + .direction_output = stmpe_gpio_direction_output, > + .get = stmpe_gpio_get_value, > + .set = stmpe_gpio_set_value, > +}; > + > +static int stmpe_gpio_probe(struct device_d *dev) > +{ > + struct stmpe_gpio_chip *stmpegpio; > + struct stmpe_client_info *ci; > + > + stmpegpio = xzalloc(sizeof(*stmpegpio)); > + > + stmpegpio->base = dev_request_mem_region(dev, 0); > + stmpegpio->chip.ops = &stmpe_gpio_ops; > + stmpegpio->ci = dev->platform_data; > + > + ci = (struct stmpe_client_info *)stmpegpio->ci; > + > + if (ci->stmpe->pdata->gpio_base) > + stmpegpio->chip.base = ci->stmpe->pdata->gpio_base; > + else > + stmpegpio->chip.base = -1; > + > + stmpegpio->chip.ngpio = 16; > + stmpegpio->chip.dev = dev; > + > + gpiochip_add(&stmpegpio->chip); > + > + dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base); > + return 0; > +} > + > +static struct driver_d stmpe_gpio_driver = { > + .name = "stmpe-gpio", > + .probe = stmpe_gpio_probe, > +}; > + > +static int stmpe_gpio_add(void) > +{ > + register_driver(&stmpe_gpio_driver); > + return 0; return register_driver(&stmpe_gpio_driver); > +} > +coredevice_initcall(stmpe_gpio_add); > -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de | [-- Attachment #1.2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 259 bytes --] [-- Attachment #2: Type: text/plain, Size: 149 bytes --] _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-09-04 8:29 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-09-03 11:03 [PATCH v2 0/2] Add stmpe mfd Steffen Trumtrar 2012-09-03 11:03 ` [PATCH v2 1/2] mfd: add stmpe-i2c driver Steffen Trumtrar 2012-09-04 8:11 ` Sascha Hauer 2012-09-04 8:18 ` Marc Kleine-Budde 2012-09-03 11:03 ` [PATCH v2 2/2] gpio: add driver for stmpe io-expander Steffen Trumtrar 2012-09-04 8:13 ` Sascha Hauer 2012-09-04 8:29 ` Marc Kleine-Budde
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox