From fe39f2f4dc8481d3aa4561ba649b0c0a4429a49e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 13 Nov 2012 19:18:07 +0530 Subject: mfd: Implement tps6586x gpio_to_irq The TPS6586x adds the interrupt of this device using linear mapping on irq domain. Hence, implement gpio_to_irq to get the irq number corresponding to TPS6586x GPIOs which is created dynamically. Signed-off-by: Laxman Dewangan Reviewed-by: Mark Brown Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-tps6586x.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 2526b3bb0fa..62e9e1cb3bc 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -80,6 +80,14 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, val, mask); } +static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); + + return tps6586x_irq_get_virq(tps6586x_gpio->parent, + TPS6586X_INT_PLDO_0 + offset); +} + static int __devinit tps6586x_gpio_probe(struct platform_device *pdev) { struct tps6586x_platform_data *pdata; @@ -106,6 +114,7 @@ static int __devinit tps6586x_gpio_probe(struct platform_device *pdev) tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; + tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq; #ifdef CONFIG_OF_GPIO tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; -- cgit v1.2.3-70-g09d2 From d511b9c3626c83874824b1118f8a2e84ef63a7d3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Oct 2012 00:15:09 -0300 Subject: gpio: gpio-da9052: Convert to the new da9052 interrupt functions Convert to the new da9052 interrupt functions, so that we can get rid of irq_base references. Cc: Grant Likely Signed-off-by: Fabio Estevam Reviewed-by: Mark Brown Reviewed-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-da9052.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 24b8c297404..63f9f5bbc75 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -185,7 +185,11 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) struct da9052_gpio *gpio = to_da9052_gpio(gc); struct da9052 *da9052 = gpio->da9052; - return da9052->irq_base + DA9052_IRQ_GPI0 + offset; + int irq; + + irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset); + + return irq; } static struct gpio_chip reference_gp __devinitdata = { -- cgit v1.2.3-70-g09d2 From 9d5b72de0d1627b130fa69c5edf58b5b2df4ca50 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Mon, 5 Nov 2012 15:48:24 +0100 Subject: gpio: Add viperboard gpio driver This adds the mfd cell to use the gpio a and gpio b part of the Nano River Technologies viperboard. Signed-off-by: Lars Poeschel Reviewed-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/gpio/Kconfig | 13 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-viperboard.c | 517 +++++++++++++++++++++++++++++++++++++++++ drivers/mfd/viperboard.c | 3 + include/linux/mfd/viperboard.h | 2 + 5 files changed, 536 insertions(+) create mode 100644 drivers/gpio/gpio-viperboard.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d055cee3694..c3bbd08bcdc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -649,4 +649,17 @@ config GPIO_MSIC Enable support for GPIO on intel MSIC controllers found in intel MID devices +comment "USB GPIO expanders:" + +config GPIO_VIPERBOARD + tristate "Viperboard GPIO a & b support" + depends on MFD_VIPERBOARD && USB + help + Say yes here to access the GPIO signals of Nano River + Technologies Viperboard. There are two GPIO chips on the + board: gpioa and gpiob. + See viperboard API specification and Nano + River Tech's viperboard.h for detailed meaning + of the module parameters. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..16a1385226e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o +obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c new file mode 100644 index 00000000000..13772996cf2 --- /dev/null +++ b/drivers/gpio/gpio-viperboard.c @@ -0,0 +1,517 @@ +/* + * Nano River Technologies viperboard GPIO lib driver + * + * (C) 2012 by Lemonage GmbH + * Author: Lars Poeschel + * All rights reserved. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define VPRBRD_GPIOA_CLK_1MHZ 0 +#define VPRBRD_GPIOA_CLK_100KHZ 1 +#define VPRBRD_GPIOA_CLK_10KHZ 2 +#define VPRBRD_GPIOA_CLK_1KHZ 3 +#define VPRBRD_GPIOA_CLK_100HZ 4 +#define VPRBRD_GPIOA_CLK_10HZ 5 + +#define VPRBRD_GPIOA_FREQ_DEFAULT 1000 + +#define VPRBRD_GPIOA_CMD_CONT 0x00 +#define VPRBRD_GPIOA_CMD_PULSE 0x01 +#define VPRBRD_GPIOA_CMD_PWM 0x02 +#define VPRBRD_GPIOA_CMD_SETOUT 0x03 +#define VPRBRD_GPIOA_CMD_SETIN 0x04 +#define VPRBRD_GPIOA_CMD_SETINT 0x05 +#define VPRBRD_GPIOA_CMD_GETIN 0x06 + +#define VPRBRD_GPIOB_CMD_SETDIR 0x00 +#define VPRBRD_GPIOB_CMD_SETVAL 0x01 + +struct vprbrd_gpioa_msg { + u8 cmd; + u8 clk; + u8 offset; + u8 t1; + u8 t2; + u8 invert; + u8 pwmlevel; + u8 outval; + u8 risefall; + u8 answer; + u8 __fill; +} __packed; + +struct vprbrd_gpiob_msg { + u8 cmd; + u16 val; + u16 mask; +} __packed; + +struct vprbrd_gpio { + struct gpio_chip gpioa; /* gpio a related things */ + u32 gpioa_out; + u32 gpioa_val; + struct gpio_chip gpiob; /* gpio b related things */ + u32 gpiob_out; + u32 gpiob_val; + struct vprbrd *vb; +}; + +/* gpioa sampling clock module parameter */ +static unsigned char gpioa_clk; +static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT; +module_param(gpioa_freq, uint, 0); +MODULE_PARM_DESC(gpioa_freq, + "gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000"); + +/* ----- begin of gipo a chip -------------------------------------------- */ + +static int vprbrd_gpioa_get(struct gpio_chip *chip, + unsigned offset) +{ + int ret, answer, error = 0; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpioa); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; + + /* if io is set to output, just return the saved value */ + if (gpio->gpioa_out & (1 << offset)) + return gpio->gpioa_val & (1 << offset); + + mutex_lock(&vb->lock); + + gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN; + gamsg->clk = 0x00; + gamsg->offset = offset; + gamsg->t1 = 0x00; + gamsg->t2 = 0x00; + gamsg->invert = 0x00; + gamsg->pwmlevel = 0x00; + gamsg->outval = 0x00; + gamsg->risefall = 0x00; + gamsg->answer = 0x00; + gamsg->__fill = 0x00; + + ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, + 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), + VPRBRD_USB_TIMEOUT_MS); + if (ret != sizeof(struct vprbrd_gpioa_msg)) + error = -EREMOTEIO; + + ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000, + 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), + VPRBRD_USB_TIMEOUT_MS); + answer = gamsg->answer & 0x01; + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpioa_msg)) + error = -EREMOTEIO; + + if (error) + return error; + + return answer; +} + +static void vprbrd_gpioa_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpioa); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; + + if (gpio->gpioa_out & (1 << offset)) { + if (value) + gpio->gpioa_val |= (1 << offset); + else + gpio->gpioa_val &= ~(1 << offset); + + mutex_lock(&vb->lock); + + gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; + gamsg->clk = 0x00; + gamsg->offset = offset; + gamsg->t1 = 0x00; + gamsg->t2 = 0x00; + gamsg->invert = 0x00; + gamsg->pwmlevel = 0x00; + gamsg->outval = value; + gamsg->risefall = 0x00; + gamsg->answer = 0x00; + gamsg->__fill = 0x00; + + ret = usb_control_msg(vb->usb_dev, + usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, + 0x0000, 0x0000, gamsg, + sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS); + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpioa_msg)) + dev_err(chip->dev, "usb error setting pin value\n"); + } +} + +static int vprbrd_gpioa_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpioa); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; + + gpio->gpioa_out &= ~(1 << offset); + + mutex_lock(&vb->lock); + + gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN; + gamsg->clk = gpioa_clk; + gamsg->offset = offset; + gamsg->t1 = 0x00; + gamsg->t2 = 0x00; + gamsg->invert = 0x00; + gamsg->pwmlevel = 0x00; + gamsg->outval = 0x00; + gamsg->risefall = 0x00; + gamsg->answer = 0x00; + gamsg->__fill = 0x00; + + ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, + 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), + VPRBRD_USB_TIMEOUT_MS); + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpioa_msg)) + return -EREMOTEIO; + + return 0; +} + +static int vprbrd_gpioa_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpioa); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; + + gpio->gpioa_out |= (1 << offset); + if (value) + gpio->gpioa_val |= (1 << offset); + else + gpio->gpioa_val &= ~(1 << offset); + + mutex_lock(&vb->lock); + + gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; + gamsg->clk = 0x00; + gamsg->offset = offset; + gamsg->t1 = 0x00; + gamsg->t2 = 0x00; + gamsg->invert = 0x00; + gamsg->pwmlevel = 0x00; + gamsg->outval = value; + gamsg->risefall = 0x00; + gamsg->answer = 0x00; + gamsg->__fill = 0x00; + + ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, + 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), + VPRBRD_USB_TIMEOUT_MS); + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpioa_msg)) + return -EREMOTEIO; + + return 0; +} + +/* ----- end of gpio a chip ---------------------------------------------- */ + +/* ----- begin of gipo b chip -------------------------------------------- */ + +static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset, + unsigned dir) +{ + struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; + int ret; + + gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR; + gbmsg->val = cpu_to_be16(dir << offset); + gbmsg->mask = cpu_to_be16(0x0001 << offset); + + ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000, + 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), + VPRBRD_USB_TIMEOUT_MS); + + if (ret != sizeof(struct vprbrd_gpiob_msg)) + return -EREMOTEIO; + + return 0; +} + +static int vprbrd_gpiob_get(struct gpio_chip *chip, + unsigned offset) +{ + int ret; + u16 val; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpiob); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) + return gpio->gpiob_val & (1 << offset); + + mutex_lock(&vb->lock); + + ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000, + 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), + VPRBRD_USB_TIMEOUT_MS); + val = gbmsg->val; + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpiob_msg)) + return ret; + + /* cache the read values */ + gpio->gpiob_val = be16_to_cpu(val); + + return (gpio->gpiob_val >> offset) & 0x1; +} + +static void vprbrd_gpiob_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpiob); + struct vprbrd *vb = gpio->vb; + struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; + + if (gpio->gpiob_out & (1 << offset)) { + if (value) + gpio->gpiob_val |= (1 << offset); + else + gpio->gpiob_val &= ~(1 << offset); + + mutex_lock(&vb->lock); + + gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL; + gbmsg->val = cpu_to_be16(value << offset); + gbmsg->mask = cpu_to_be16(0x0001 << offset); + + ret = usb_control_msg(vb->usb_dev, + usb_sndctrlpipe(vb->usb_dev, 0), + VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, + 0x0000, 0x0000, gbmsg, + sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS); + + mutex_unlock(&vb->lock); + + if (ret != sizeof(struct vprbrd_gpiob_msg)) + dev_err(chip->dev, "usb error setting pin value\n"); + } +} + +static int vprbrd_gpiob_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpiob); + struct vprbrd *vb = gpio->vb; + + gpio->gpiob_out &= ~(1 << offset); + + mutex_lock(&vb->lock); + + ret = vprbrd_gpiob_setdir(vb, offset, 0); + + mutex_unlock(&vb->lock); + + if (ret) + dev_err(chip->dev, "usb error setting pin to input\n"); + + return ret; +} + +static int vprbrd_gpiob_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + int ret; + struct vprbrd_gpio *gpio = + container_of(chip, struct vprbrd_gpio, gpiob); + struct vprbrd *vb = gpio->vb; + + gpio->gpiob_out |= (1 << offset); + if (value) + gpio->gpiob_val |= (1 << offset); + else + gpio->gpiob_val &= ~(1 << offset); + + mutex_lock(&vb->lock); + + ret = vprbrd_gpiob_setdir(vb, offset, 1); + if (ret) + dev_err(chip->dev, "usb error setting pin to output\n"); + + mutex_unlock(&vb->lock); + + vprbrd_gpiob_set(chip, offset, value); + + return ret; +} + +/* ----- end of gpio b chip ---------------------------------------------- */ + +static int __devinit vprbrd_gpio_probe(struct platform_device *pdev) +{ + struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); + struct vprbrd_gpio *vb_gpio; + int ret; + + vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL); + if (vb_gpio == NULL) + return -ENOMEM; + + vb_gpio->vb = vb; + /* registering gpio a */ + vb_gpio->gpioa.label = "viperboard gpio a"; + vb_gpio->gpioa.dev = &pdev->dev; + vb_gpio->gpioa.owner = THIS_MODULE; + vb_gpio->gpioa.base = -1; + vb_gpio->gpioa.ngpio = 16; + vb_gpio->gpioa.can_sleep = 1; + vb_gpio->gpioa.set = vprbrd_gpioa_set; + vb_gpio->gpioa.get = vprbrd_gpioa_get; + vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; + vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output; + ret = gpiochip_add(&vb_gpio->gpioa); + if (ret < 0) { + dev_err(vb_gpio->gpioa.dev, "could not add gpio a"); + goto err_gpioa; + } + + /* registering gpio b */ + vb_gpio->gpiob.label = "viperboard gpio b"; + vb_gpio->gpiob.dev = &pdev->dev; + vb_gpio->gpiob.owner = THIS_MODULE; + vb_gpio->gpiob.base = -1; + vb_gpio->gpiob.ngpio = 16; + vb_gpio->gpiob.can_sleep = 1; + vb_gpio->gpiob.set = vprbrd_gpiob_set; + vb_gpio->gpiob.get = vprbrd_gpiob_get; + vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; + vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output; + ret = gpiochip_add(&vb_gpio->gpiob); + if (ret < 0) { + dev_err(vb_gpio->gpiob.dev, "could not add gpio b"); + goto err_gpiob; + } + + platform_set_drvdata(pdev, vb_gpio); + + return ret; + +err_gpiob: + ret = gpiochip_remove(&vb_gpio->gpioa); + +err_gpioa: + return ret; +} + +static int __devexit vprbrd_gpio_remove(struct platform_device *pdev) +{ + struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&vb_gpio->gpiob); + if (ret == 0) + ret = gpiochip_remove(&vb_gpio->gpioa); + + return ret; +} + +static struct platform_driver vprbrd_gpio_driver = { + .driver.name = "viperboard-gpio", + .driver.owner = THIS_MODULE, + .probe = vprbrd_gpio_probe, + .remove = __devexit_p(vprbrd_gpio_remove), +}; + +static int __init vprbrd_gpio_init(void) +{ + switch (gpioa_freq) { + case 1000000: + gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ; + break; + case 100000: + gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ; + break; + case 10000: + gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ; + break; + case 1000: + gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; + break; + case 100: + gpioa_clk = VPRBRD_GPIOA_CLK_100HZ; + break; + case 10: + gpioa_clk = VPRBRD_GPIOA_CLK_10HZ; + break; + default: + pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq); + gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; + } + + return platform_driver_register(&vprbrd_gpio_driver); +} +subsys_initcall(vprbrd_gpio_init); + +static void __exit vprbrd_gpio_exit(void) +{ + platform_driver_unregister(&vprbrd_gpio_driver); +} +module_exit(vprbrd_gpio_exit); + +MODULE_AUTHOR("Lars Poeschel "); +MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:viperboard-gpio"); diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c index cd1e2fe9564..c75ac08f639 100644 --- a/drivers/mfd/viperboard.c +++ b/drivers/mfd/viperboard.c @@ -38,6 +38,9 @@ static const struct usb_device_id vprbrd_table[] = { MODULE_DEVICE_TABLE(usb, vprbrd_table); static struct mfd_cell vprbrd_devs[] = { + { + .name = "viperboard-gpio", + }, }; static int vprbrd_probe(struct usb_interface *interface, diff --git a/include/linux/mfd/viperboard.h b/include/linux/mfd/viperboard.h index 0d1342466db..42d339fac3e 100644 --- a/include/linux/mfd/viperboard.h +++ b/include/linux/mfd/viperboard.h @@ -44,6 +44,8 @@ #define VPRBRD_USB_TIMEOUT_MS 100 #define VPRBRD_USB_REQUEST_MAJOR 0xea #define VPRBRD_USB_REQUEST_MINOR 0xeb +#define VPRBRD_USB_REQUEST_GPIOA 0xed +#define VPRBRD_USB_REQUEST_GPIOB 0xdd struct vprbrd_i2c_write_hdr { u8 cmd; -- cgit v1.2.3-70-g09d2 From 14591d888e35c12b15eccf54e490c7769eb6d6d2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Nov 2012 09:28:45 +0100 Subject: mfd/rtc/gpio: twl: No need to allocate bigger buffer for write Since the twl-core has been converted to use regmap it is no longer needed to allocate bigger buffer for data when writing to twl. CC: Grant Likely CC: Alessandro Zummo Acked-by: Linus Walleij Acked-by: Tero Kristo Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-twl4030.c | 12 ++++++------ drivers/mfd/twl-core.c | 9 ++------- drivers/mfd/twl4030-irq.c | 6 +++--- drivers/mfd/twl6030-irq.c | 4 ++-- drivers/rtc/rtc-twl.c | 32 ++++++++++++++++---------------- 5 files changed, 29 insertions(+), 34 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index c5f8ca233e1..88829c3337b 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -354,13 +354,13 @@ static struct gpio_chip twl_gpiochip = { static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) { - u8 message[6]; + u8 message[5]; unsigned i, gpio_bit; /* For most pins, a pulldown was enabled by default. * We should have data that's specific to this board. */ - for (gpio_bit = 1, i = 1; i < 6; i++) { + for (gpio_bit = 1, i = 0; i < 5; i++) { u8 bit_mask; unsigned j; @@ -379,16 +379,16 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) { - u8 message[4]; + u8 message[3]; /* 30 msec of debouncing is always used for MMC card detect, * and is optional for everything else. */ - message[1] = (debounce & 0xff) | (mmc_cd & 0x03); + message[0] = (debounce & 0xff) | (mmc_cd & 0x03); debounce >>= 8; - message[2] = (debounce & 0xff); + message[1] = (debounce & 0xff); debounce >>= 8; - message[3] = (debounce & 0x03); + message[2] = (debounce & 0x03); return twl_i2c_write(TWL4030_MODULE_GPIO, message, REG_GPIO_DEBEN1, 3); diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 5043f505a23..a55ab15ecf1 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -344,7 +344,7 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) twl = &twl_modules[sid]; ret = regmap_bulk_write(twl->regmap, twl_map[mod_no].base + reg, - &value[1], num_bytes); + value, num_bytes); if (ret) pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", @@ -406,12 +406,7 @@ EXPORT_SYMBOL(twl_i2c_read); */ int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg) { - - /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ - u8 temp_buffer[2] = { 0 }; - /* offset 1 contains the data */ - temp_buffer[1] = value; - return twl_i2c_write(mod_no, temp_buffer, reg, 1); + return twl_i2c_write(mod_no, &value, reg, 1); } EXPORT_SYMBOL(twl_i2c_write_u8); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index ad733d76207..e900402633f 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -501,7 +501,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) } imr; /* byte[0] gets overwritten as we write ... */ - imr.word = cpu_to_le32(agent->imr << 8); + imr.word = cpu_to_le32(agent->imr); agent->imr_change_pending = false; /* write the whole mask ... simpler than subsetting it */ @@ -526,7 +526,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) * any processor on the other IRQ line, EDR registers are * shared. */ - status = twl_i2c_read(sih->module, bytes + 1, + status = twl_i2c_read(sih->module, bytes, sih->edr_offset, sih->bytes_edr); if (status) { pr_err("twl4030: %s, %s --> %d\n", __func__, @@ -538,7 +538,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) while (edge_change) { int i = fls(edge_change) - 1; struct irq_data *idata; - int byte = 1 + (i >> 2); + int byte = i >> 2; int off = (i & 0x3) * 2; unsigned int type; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index b76902f1e44..277a8dba42d 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -355,7 +355,7 @@ int twl6030_init_irq(struct device *dev, int irq_num) static struct irq_chip twl6030_irq_chip; int status = 0; int i; - u8 mask[4]; + u8 mask[3]; nr_irqs = TWL6030_NR_IRQS; @@ -370,9 +370,9 @@ int twl6030_init_irq(struct device *dev, int irq_num) irq_end = irq_base + nr_irqs; + mask[0] = 0xFF; mask[1] = 0xFF; mask[2] = 0xFF; - mask[3] = 0xFF; /* mask all int lines */ twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 9277d945bf4..8b7464c8b5c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -233,7 +233,7 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) */ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; u8 save_control; u8 rtc_control; @@ -300,15 +300,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char save_control; - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; - rtc_data[1] = bin2bcd(tm->tm_sec); - rtc_data[2] = bin2bcd(tm->tm_min); - rtc_data[3] = bin2bcd(tm->tm_hour); - rtc_data[4] = bin2bcd(tm->tm_mday); - rtc_data[5] = bin2bcd(tm->tm_mon + 1); - rtc_data[6] = bin2bcd(tm->tm_year - 100); + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); /* Stop RTC while updating the TC registers */ ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); @@ -341,7 +341,7 @@ out: */ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, @@ -368,19 +368,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char alarm_data[ALL_TIME_REGS + 1]; + unsigned char alarm_data[ALL_TIME_REGS]; int ret; ret = twl_rtc_alarm_irq_enable(dev, 0); if (ret) goto out; - alarm_data[1] = bin2bcd(alm->time.tm_sec); - alarm_data[2] = bin2bcd(alm->time.tm_min); - alarm_data[3] = bin2bcd(alm->time.tm_hour); - alarm_data[4] = bin2bcd(alm->time.tm_mday); - alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); - alarm_data[6] = bin2bcd(alm->time.tm_year - 100); + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); /* update all the alarm registers in one shot */ ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, -- cgit v1.2.3-70-g09d2