* [PATCH 1/2] regmap: Add regmap_write_bits() function
@ 2016-11-15 6:21 Andrey Smirnov
2016-11-15 6:21 ` [PATCH 2/2] gpio: Port SX150x driver from Linux Andrey Smirnov
2016-11-17 6:41 ` [PATCH 1/2] regmap: Add regmap_write_bits() function Sascha Hauer
0 siblings, 2 replies; 3+ messages in thread
From: Andrey Smirnov @ 2016-11-15 6:21 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Add code implementing a simple version of regmap_write_bits().
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/base/regmap/regmap.c | 27 +++++++++++++++++++++++++++
include/regmap.h | 6 +++++-
2 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a042a1a..52b7d88 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -137,6 +137,33 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
}
/**
+ * regmap_write_bits - write bits of a register in a map
+ *
+ * @map: The map
+ * @reg: The register offset of the register
+ * @mask: Mask indicating bits to be modified
+ * (1 - modified, 0 - untouched)
+ * @val: Bit value to be set
+ *
+ * Returns 0 for success or negative error code on failure
+ */
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ int ret;
+ unsigned int tmp, orig;
+
+ ret = regmap_read(map, reg, &orig);
+ if (ret != 0)
+ return ret;
+
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+
+ return regmap_write(map, reg, tmp);
+}
+
+/**
* regmap_bulk_read(): Read data from the device
*
* @map: Register map to read from
diff --git a/include/regmap.h b/include/regmap.h
index bcbe6c1..9675a17 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -60,4 +60,8 @@ int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map);
-#endif /* __REGMAP_H */
\ No newline at end of file
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val);
+
+
+#endif /* __REGMAP_H */
--
2.5.5
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/2] gpio: Port SX150x driver from Linux
2016-11-15 6:21 [PATCH 1/2] regmap: Add regmap_write_bits() function Andrey Smirnov
@ 2016-11-15 6:21 ` Andrey Smirnov
2016-11-17 6:41 ` [PATCH 1/2] regmap: Add regmap_write_bits() function Sascha Hauer
1 sibling, 0 replies; 3+ messages in thread
From: Andrey Smirnov @ 2016-11-15 6:21 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Add a very abridged version of SX150x driver from Linux. New, "pinctrl"
version of the driver was used as a base. As it was already mentioned
this driver supports very limited amount of the original functionality,
and the following are the features that were dropped:
- Interrupt support
- Support for any chip other that SX150x (due to lack of HW to test
with)
- Any pinctlr-like functions: pull-up/pull-down, open-drain,
etc. configuration
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/gpio/Kconfig | 8 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-sx150x.c | 274 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 283 insertions(+)
create mode 100644 drivers/gpio/gpio-sx150x.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index fe62778..434c568 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -124,6 +124,14 @@ config GPIO_DESIGNWARE
help
Say Y or M here to build support for the Synopsys DesignWare APB
GPIO block.
+
+config GPIO_SX150X
+ bool "Semtec SX150x I/O ports"
+ depends on I2C
+ help
+ Say Y here to build support for the Semtec Sx150x I2C GPIO
+ expander chip.
+
endmenu
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 248100f..7442c44 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
+obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
new file mode 100644
index 0000000..7b8cfb5
--- /dev/null
+++ b/drivers/gpio/gpio-sx150x.c
@@ -0,0 +1,274 @@
+/*
+ * Driver for SX150x I2C GPIO expanders
+ *
+ * This code was ported from linux-4.9 kernel driver by
+ * Andrey Smirnov <andrew.smirnov@gmail.com>.
+ *
+ * Orginal code with it's copyright info can be found in
+ * drivers/pinctrl/pinctrl-sx150x.c
+ *
+ * Note: That although linux driver was converted from being a GPIO
+ * subsystem to Pinctrl subsytem driver, due to Barebox's lack of
+ * similar provisions this driver is still a GPIO driver.
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <regmap.h>
+
+#include <gpio.h>
+#include <of_device.h>
+
+enum {
+ SX150X_123 = 0,
+ SX150X_456,
+ SX150X_789,
+};
+
+enum {
+ SX150X_MAX_REGISTER = 0xad,
+};
+
+struct sx150x_device_data {
+ u8 model;
+ u8 reg_dir;
+ u8 reg_data;
+ u8 ngpios;
+};
+
+struct sx150x_gpio {
+ struct device *dev;
+ struct i2c_client *client;
+ struct gpio_chip gpio;
+ struct regmap *regmap;
+ const struct sx150x_device_data *data;
+};
+
+static const struct sx150x_device_data sx1503q_device_data = {
+ .model = SX150X_123,
+ .reg_dir = 0x02,
+ .reg_data = 0x00,
+ .ngpios = 16,
+};
+
+static struct sx150x_gpio *to_sx150x_gpio(struct gpio_chip *gpio)
+{
+ return container_of(gpio, struct sx150x_gpio, gpio);
+}
+
+static int sx150x_gpio_get_direction(struct gpio_chip *gpio,
+ unsigned int offset)
+{
+ struct sx150x_gpio *sx150x = to_sx150x_gpio(gpio);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(sx150x->regmap, sx150x->data->reg_dir, &value);
+ if (ret < 0)
+ return ret;
+
+ return !!(value & BIT(offset));
+}
+
+static int sx150x_gpio_get(struct gpio_chip *gpio, unsigned int offset)
+{
+ struct sx150x_gpio *sx150x = to_sx150x_gpio(gpio);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(sx150x->regmap, sx150x->data->reg_data, &value);
+ if (ret < 0)
+ return ret;
+
+ return !!(value & BIT(offset));
+}
+
+static int __sx150x_gpio_set(struct sx150x_gpio *sx150x, unsigned int offset,
+ int value)
+{
+ return regmap_write_bits(sx150x->regmap, sx150x->data->reg_data,
+ BIT(offset), value ? BIT(offset) : 0);
+}
+
+
+static void sx150x_gpio_set(struct gpio_chip *gpio, unsigned int offset,
+ int value)
+{
+ __sx150x_gpio_set(to_sx150x_gpio(gpio), offset, value);
+}
+
+static int sx150x_gpio_direction_input(struct gpio_chip *gpio,
+ unsigned int offset)
+{
+ struct sx150x_gpio *sx150x = to_sx150x_gpio(gpio);
+
+ return regmap_write_bits(sx150x->regmap,
+ sx150x->data->reg_dir,
+ BIT(offset), BIT(offset));
+}
+
+static int sx150x_gpio_direction_output(struct gpio_chip *gpio,
+ unsigned int offset, int value)
+{
+ struct sx150x_gpio *sx150x = to_sx150x_gpio(gpio);
+ int ret;
+
+ ret = __sx150x_gpio_set(sx150x, offset, value);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write_bits(sx150x->regmap,
+ sx150x->data->reg_dir,
+ BIT(offset), 0);
+}
+
+static int sx150x_regmap_reg_width(struct sx150x_gpio *sx150x,
+ unsigned int reg)
+{
+ return sx150x->data->ngpios;
+}
+
+/*
+ * In order to mask the differences between 16 and 8 bit expander
+ * devices we set up a sligthly ficticious regmap that pretends to be
+ * a set of 16-bit registers and transparently reconstructs those
+ * registers via multiple I2C/SMBus reads
+ *
+ * This way the rest of the driver code, interfacing with the chip via
+ * regmap API, can work assuming that each GPIO pin is represented by
+ * a group of bits at an offset proportioan to GPIO number within a
+ * given register.
+ *
+ */
+static int sx150x_regmap_reg_read(void *context, unsigned int reg,
+ unsigned int *result)
+{
+ int ret, n;
+ struct sx150x_gpio *sx150x = context;
+ struct i2c_client *i2c = sx150x->client;
+ const int width = sx150x_regmap_reg_width(sx150x, reg);
+ unsigned int idx, val;
+
+ /*
+ * There are four potential cases coverd by this function:
+ *
+ * 1) 8-pin chip, single configuration bit register
+ *
+ * This is trivial the code below just needs to read:
+ * reg [ 7 6 5 4 3 2 1 0 ]
+ *
+ * 2) 16-pin chip, single configuration bit register
+ *
+ * The read will be done as follows:
+ * reg [ f e d c b a 9 8 ]
+ * reg + 1 [ 7 6 5 4 3 2 1 0 ]
+ *
+ */
+
+ for (n = width, val = 0, idx = reg; n > 0; n -= 8, idx++) {
+ val <<= 8;
+
+ ret = i2c_smbus_read_byte_data(i2c, idx);
+ if (ret < 0)
+ return ret;
+
+ val |= ret;
+ }
+
+ *result = val;
+
+ return 0;
+}
+
+static int sx150x_regmap_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int ret, n;
+ struct sx150x_gpio *sx150x = context;
+ struct i2c_client *i2c = sx150x->client;
+ const int width = sx150x_regmap_reg_width(sx150x, reg);
+
+ n = width - 8;
+ do {
+ const u8 byte = (val >> n) & 0xff;
+
+ ret = i2c_smbus_write_byte_data(i2c, reg, byte);
+ if (ret < 0)
+ return ret;
+
+ reg++;
+ n -= 8;
+ } while (n >= 0);
+
+ return 0;
+}
+
+static const struct regmap_config sx150x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = SX150X_MAX_REGISTER,
+};
+
+static const struct regmap_bus sx150x_regmap_bus = {
+ .reg_read = sx150x_regmap_reg_read,
+ .reg_write = sx150x_regmap_reg_write,
+};
+
+static struct gpio_ops sx150x_gpio_ops = {
+ .direction_input = sx150x_gpio_direction_input,
+ .direction_output = sx150x_gpio_direction_output,
+ .get_direction = sx150x_gpio_get_direction,
+ .get = sx150x_gpio_get,
+ .set = sx150x_gpio_set,
+};
+
+static int sx150x_probe(struct device_d *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct sx150x_gpio *sx150x;
+ const struct sx150x_device_data *data;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ sx150x = xzalloc(sizeof(*sx150x));
+
+ sx150x->regmap = regmap_init(dev, &sx150x_regmap_bus,
+ sx150x, &sx150x_regmap_config);
+ sx150x->client = client;
+ sx150x->data = data;
+ sx150x->gpio.ops = &sx150x_gpio_ops;
+ sx150x->gpio.base = -1;
+ sx150x->gpio.ngpio = sx150x->data->ngpios;
+ sx150x->gpio.dev = &client->dev;
+
+ return gpiochip_add(&sx150x->gpio);
+}
+
+static __maybe_unused struct of_device_id sx150x_dt_ids[] = {
+ { .compatible = "semtech,sx1503q", .data = &sx1503q_device_data, },
+ { }
+};
+
+static struct driver_d sx150x_driver = {
+ .name = "sx150x",
+ .probe = sx150x_probe,
+ .of_compatible = sx150x_dt_ids,
+};
+
+static int __init sx150x_init(void)
+{
+ return i2c_driver_register(&sx150x_driver);
+}
+device_initcall(sx150x_init);
--
2.5.5
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 1/2] regmap: Add regmap_write_bits() function
2016-11-15 6:21 [PATCH 1/2] regmap: Add regmap_write_bits() function Andrey Smirnov
2016-11-15 6:21 ` [PATCH 2/2] gpio: Port SX150x driver from Linux Andrey Smirnov
@ 2016-11-17 6:41 ` Sascha Hauer
1 sibling, 0 replies; 3+ messages in thread
From: Sascha Hauer @ 2016-11-17 6:41 UTC (permalink / raw)
To: Andrey Smirnov; +Cc: barebox
On Mon, Nov 14, 2016 at 10:21:13PM -0800, Andrey Smirnov wrote:
> Add code implementing a simple version of regmap_write_bits().
>
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
> drivers/base/regmap/regmap.c | 27 +++++++++++++++++++++++++++
> include/regmap.h | 6 +++++-
> 2 files changed, 32 insertions(+), 1 deletion(-)
Applied, thanks
Sascha
>
> diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
> index a042a1a..52b7d88 100644
> --- a/drivers/base/regmap/regmap.c
> +++ b/drivers/base/regmap/regmap.c
> @@ -137,6 +137,33 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
> }
>
> /**
> + * regmap_write_bits - write bits of a register in a map
> + *
> + * @map: The map
> + * @reg: The register offset of the register
> + * @mask: Mask indicating bits to be modified
> + * (1 - modified, 0 - untouched)
> + * @val: Bit value to be set
> + *
> + * Returns 0 for success or negative error code on failure
> + */
> +int regmap_write_bits(struct regmap *map, unsigned int reg,
> + unsigned int mask, unsigned int val)
> +{
> + int ret;
> + unsigned int tmp, orig;
> +
> + ret = regmap_read(map, reg, &orig);
> + if (ret != 0)
> + return ret;
> +
> + tmp = orig & ~mask;
> + tmp |= val & mask;
> +
> + return regmap_write(map, reg, tmp);
> +}
> +
> +/**
> * regmap_bulk_read(): Read data from the device
> *
> * @map: Register map to read from
> diff --git a/include/regmap.h b/include/regmap.h
> index bcbe6c1..9675a17 100644
> --- a/include/regmap.h
> +++ b/include/regmap.h
> @@ -60,4 +60,8 @@ int regmap_get_val_bytes(struct regmap *map);
> int regmap_get_max_register(struct regmap *map);
> int regmap_get_reg_stride(struct regmap *map);
>
> -#endif /* __REGMAP_H */
> \ No newline at end of file
> +int regmap_write_bits(struct regmap *map, unsigned int reg,
> + unsigned int mask, unsigned int val);
> +
> +
> +#endif /* __REGMAP_H */
> --
> 2.5.5
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
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] 3+ messages in thread
end of thread, other threads:[~2016-11-17 6:41 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-15 6:21 [PATCH 1/2] regmap: Add regmap_write_bits() function Andrey Smirnov
2016-11-15 6:21 ` [PATCH 2/2] gpio: Port SX150x driver from Linux Andrey Smirnov
2016-11-17 6:41 ` [PATCH 1/2] regmap: Add regmap_write_bits() function Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox