19d5b72deSLars Poeschel /* 29d5b72deSLars Poeschel * Nano River Technologies viperboard GPIO lib driver 39d5b72deSLars Poeschel * 49d5b72deSLars Poeschel * (C) 2012 by Lemonage GmbH 59d5b72deSLars Poeschel * Author: Lars Poeschel <poeschel@lemonage.de> 69d5b72deSLars Poeschel * All rights reserved. 79d5b72deSLars Poeschel * 89d5b72deSLars Poeschel * This program is free software; you can redistribute it and/or modify it 99d5b72deSLars Poeschel * under the terms of the GNU General Public License as published by the 109d5b72deSLars Poeschel * Free Software Foundation; either version 2 of the License, or (at your 119d5b72deSLars Poeschel * option) any later version. 129d5b72deSLars Poeschel * 139d5b72deSLars Poeschel */ 149d5b72deSLars Poeschel 159d5b72deSLars Poeschel #include <linux/kernel.h> 169d5b72deSLars Poeschel #include <linux/errno.h> 179d5b72deSLars Poeschel #include <linux/module.h> 189d5b72deSLars Poeschel #include <linux/slab.h> 199d5b72deSLars Poeschel #include <linux/types.h> 209d5b72deSLars Poeschel #include <linux/mutex.h> 219d5b72deSLars Poeschel #include <linux/platform_device.h> 229d5b72deSLars Poeschel 239d5b72deSLars Poeschel #include <linux/usb.h> 249d5b72deSLars Poeschel #include <linux/gpio.h> 259d5b72deSLars Poeschel 269d5b72deSLars Poeschel #include <linux/mfd/viperboard.h> 279d5b72deSLars Poeschel 289d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_1MHZ 0 299d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_100KHZ 1 309d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_10KHZ 2 319d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_1KHZ 3 329d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_100HZ 4 339d5b72deSLars Poeschel #define VPRBRD_GPIOA_CLK_10HZ 5 349d5b72deSLars Poeschel 359d5b72deSLars Poeschel #define VPRBRD_GPIOA_FREQ_DEFAULT 1000 369d5b72deSLars Poeschel 379d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_CONT 0x00 389d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_PULSE 0x01 399d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_PWM 0x02 409d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_SETOUT 0x03 419d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_SETIN 0x04 429d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_SETINT 0x05 439d5b72deSLars Poeschel #define VPRBRD_GPIOA_CMD_GETIN 0x06 449d5b72deSLars Poeschel 459d5b72deSLars Poeschel #define VPRBRD_GPIOB_CMD_SETDIR 0x00 469d5b72deSLars Poeschel #define VPRBRD_GPIOB_CMD_SETVAL 0x01 479d5b72deSLars Poeschel 489d5b72deSLars Poeschel struct vprbrd_gpioa_msg { 499d5b72deSLars Poeschel u8 cmd; 509d5b72deSLars Poeschel u8 clk; 519d5b72deSLars Poeschel u8 offset; 529d5b72deSLars Poeschel u8 t1; 539d5b72deSLars Poeschel u8 t2; 549d5b72deSLars Poeschel u8 invert; 559d5b72deSLars Poeschel u8 pwmlevel; 569d5b72deSLars Poeschel u8 outval; 579d5b72deSLars Poeschel u8 risefall; 589d5b72deSLars Poeschel u8 answer; 599d5b72deSLars Poeschel u8 __fill; 609d5b72deSLars Poeschel } __packed; 619d5b72deSLars Poeschel 629d5b72deSLars Poeschel struct vprbrd_gpiob_msg { 639d5b72deSLars Poeschel u8 cmd; 649d5b72deSLars Poeschel u16 val; 659d5b72deSLars Poeschel u16 mask; 669d5b72deSLars Poeschel } __packed; 679d5b72deSLars Poeschel 689d5b72deSLars Poeschel struct vprbrd_gpio { 699d5b72deSLars Poeschel struct gpio_chip gpioa; /* gpio a related things */ 709d5b72deSLars Poeschel u32 gpioa_out; 719d5b72deSLars Poeschel u32 gpioa_val; 729d5b72deSLars Poeschel struct gpio_chip gpiob; /* gpio b related things */ 739d5b72deSLars Poeschel u32 gpiob_out; 749d5b72deSLars Poeschel u32 gpiob_val; 759d5b72deSLars Poeschel struct vprbrd *vb; 769d5b72deSLars Poeschel }; 779d5b72deSLars Poeschel 789d5b72deSLars Poeschel /* gpioa sampling clock module parameter */ 799d5b72deSLars Poeschel static unsigned char gpioa_clk; 809d5b72deSLars Poeschel static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT; 819d5b72deSLars Poeschel module_param(gpioa_freq, uint, 0); 829d5b72deSLars Poeschel MODULE_PARM_DESC(gpioa_freq, 839d5b72deSLars Poeschel "gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000"); 849d5b72deSLars Poeschel 859d5b72deSLars Poeschel /* ----- begin of gipo a chip -------------------------------------------- */ 869d5b72deSLars Poeschel 879d5b72deSLars Poeschel static int vprbrd_gpioa_get(struct gpio_chip *chip, 889d5b72deSLars Poeschel unsigned offset) 899d5b72deSLars Poeschel { 909d5b72deSLars Poeschel int ret, answer, error = 0; 919d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 929d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpioa); 939d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 949d5b72deSLars Poeschel struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 959d5b72deSLars Poeschel 969d5b72deSLars Poeschel /* if io is set to output, just return the saved value */ 979d5b72deSLars Poeschel if (gpio->gpioa_out & (1 << offset)) 989d5b72deSLars Poeschel return gpio->gpioa_val & (1 << offset); 999d5b72deSLars Poeschel 1009d5b72deSLars Poeschel mutex_lock(&vb->lock); 1019d5b72deSLars Poeschel 1029d5b72deSLars Poeschel gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN; 1039d5b72deSLars Poeschel gamsg->clk = 0x00; 1049d5b72deSLars Poeschel gamsg->offset = offset; 1059d5b72deSLars Poeschel gamsg->t1 = 0x00; 1069d5b72deSLars Poeschel gamsg->t2 = 0x00; 1079d5b72deSLars Poeschel gamsg->invert = 0x00; 1089d5b72deSLars Poeschel gamsg->pwmlevel = 0x00; 1099d5b72deSLars Poeschel gamsg->outval = 0x00; 1109d5b72deSLars Poeschel gamsg->risefall = 0x00; 1119d5b72deSLars Poeschel gamsg->answer = 0x00; 1129d5b72deSLars Poeschel gamsg->__fill = 0x00; 1139d5b72deSLars Poeschel 1149d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 1159d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 1169d5b72deSLars Poeschel 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 1179d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 1189d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpioa_msg)) 1199d5b72deSLars Poeschel error = -EREMOTEIO; 1209d5b72deSLars Poeschel 1219d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), 1229d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000, 1239d5b72deSLars Poeschel 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 1249d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 1259d5b72deSLars Poeschel answer = gamsg->answer & 0x01; 1269d5b72deSLars Poeschel 1279d5b72deSLars Poeschel mutex_unlock(&vb->lock); 1289d5b72deSLars Poeschel 1299d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpioa_msg)) 1309d5b72deSLars Poeschel error = -EREMOTEIO; 1319d5b72deSLars Poeschel 1329d5b72deSLars Poeschel if (error) 1339d5b72deSLars Poeschel return error; 1349d5b72deSLars Poeschel 1359d5b72deSLars Poeschel return answer; 1369d5b72deSLars Poeschel } 1379d5b72deSLars Poeschel 1389d5b72deSLars Poeschel static void vprbrd_gpioa_set(struct gpio_chip *chip, 1399d5b72deSLars Poeschel unsigned offset, int value) 1409d5b72deSLars Poeschel { 1419d5b72deSLars Poeschel int ret; 1429d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 1439d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpioa); 1449d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 1459d5b72deSLars Poeschel struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 1469d5b72deSLars Poeschel 1479d5b72deSLars Poeschel if (gpio->gpioa_out & (1 << offset)) { 1489d5b72deSLars Poeschel if (value) 1499d5b72deSLars Poeschel gpio->gpioa_val |= (1 << offset); 1509d5b72deSLars Poeschel else 1519d5b72deSLars Poeschel gpio->gpioa_val &= ~(1 << offset); 1529d5b72deSLars Poeschel 1539d5b72deSLars Poeschel mutex_lock(&vb->lock); 1549d5b72deSLars Poeschel 1559d5b72deSLars Poeschel gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; 1569d5b72deSLars Poeschel gamsg->clk = 0x00; 1579d5b72deSLars Poeschel gamsg->offset = offset; 1589d5b72deSLars Poeschel gamsg->t1 = 0x00; 1599d5b72deSLars Poeschel gamsg->t2 = 0x00; 1609d5b72deSLars Poeschel gamsg->invert = 0x00; 1619d5b72deSLars Poeschel gamsg->pwmlevel = 0x00; 1629d5b72deSLars Poeschel gamsg->outval = value; 1639d5b72deSLars Poeschel gamsg->risefall = 0x00; 1649d5b72deSLars Poeschel gamsg->answer = 0x00; 1659d5b72deSLars Poeschel gamsg->__fill = 0x00; 1669d5b72deSLars Poeschel 1679d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, 1689d5b72deSLars Poeschel usb_sndctrlpipe(vb->usb_dev, 0), 1699d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 1709d5b72deSLars Poeschel 0x0000, 0x0000, gamsg, 1719d5b72deSLars Poeschel sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS); 1729d5b72deSLars Poeschel 1739d5b72deSLars Poeschel mutex_unlock(&vb->lock); 1749d5b72deSLars Poeschel 1759d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpioa_msg)) 17658383c78SLinus Walleij dev_err(chip->parent, "usb error setting pin value\n"); 1779d5b72deSLars Poeschel } 1789d5b72deSLars Poeschel } 1799d5b72deSLars Poeschel 1809d5b72deSLars Poeschel static int vprbrd_gpioa_direction_input(struct gpio_chip *chip, 1819d5b72deSLars Poeschel unsigned offset) 1829d5b72deSLars Poeschel { 1839d5b72deSLars Poeschel int ret; 1849d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 1859d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpioa); 1869d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 1879d5b72deSLars Poeschel struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 1889d5b72deSLars Poeschel 1899d5b72deSLars Poeschel gpio->gpioa_out &= ~(1 << offset); 1909d5b72deSLars Poeschel 1919d5b72deSLars Poeschel mutex_lock(&vb->lock); 1929d5b72deSLars Poeschel 1939d5b72deSLars Poeschel gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN; 1949d5b72deSLars Poeschel gamsg->clk = gpioa_clk; 1959d5b72deSLars Poeschel gamsg->offset = offset; 1969d5b72deSLars Poeschel gamsg->t1 = 0x00; 1979d5b72deSLars Poeschel gamsg->t2 = 0x00; 1989d5b72deSLars Poeschel gamsg->invert = 0x00; 1999d5b72deSLars Poeschel gamsg->pwmlevel = 0x00; 2009d5b72deSLars Poeschel gamsg->outval = 0x00; 2019d5b72deSLars Poeschel gamsg->risefall = 0x00; 2029d5b72deSLars Poeschel gamsg->answer = 0x00; 2039d5b72deSLars Poeschel gamsg->__fill = 0x00; 2049d5b72deSLars Poeschel 2059d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 2069d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 2079d5b72deSLars Poeschel 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 2089d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 2099d5b72deSLars Poeschel 2109d5b72deSLars Poeschel mutex_unlock(&vb->lock); 2119d5b72deSLars Poeschel 2129d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpioa_msg)) 2139d5b72deSLars Poeschel return -EREMOTEIO; 2149d5b72deSLars Poeschel 2159d5b72deSLars Poeschel return 0; 2169d5b72deSLars Poeschel } 2179d5b72deSLars Poeschel 2189d5b72deSLars Poeschel static int vprbrd_gpioa_direction_output(struct gpio_chip *chip, 2199d5b72deSLars Poeschel unsigned offset, int value) 2209d5b72deSLars Poeschel { 2219d5b72deSLars Poeschel int ret; 2229d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 2239d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpioa); 2249d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 2259d5b72deSLars Poeschel struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 2269d5b72deSLars Poeschel 2279d5b72deSLars Poeschel gpio->gpioa_out |= (1 << offset); 2289d5b72deSLars Poeschel if (value) 2299d5b72deSLars Poeschel gpio->gpioa_val |= (1 << offset); 2309d5b72deSLars Poeschel else 2319d5b72deSLars Poeschel gpio->gpioa_val &= ~(1 << offset); 2329d5b72deSLars Poeschel 2339d5b72deSLars Poeschel mutex_lock(&vb->lock); 2349d5b72deSLars Poeschel 2359d5b72deSLars Poeschel gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; 2369d5b72deSLars Poeschel gamsg->clk = 0x00; 2379d5b72deSLars Poeschel gamsg->offset = offset; 2389d5b72deSLars Poeschel gamsg->t1 = 0x00; 2399d5b72deSLars Poeschel gamsg->t2 = 0x00; 2409d5b72deSLars Poeschel gamsg->invert = 0x00; 2419d5b72deSLars Poeschel gamsg->pwmlevel = 0x00; 2429d5b72deSLars Poeschel gamsg->outval = value; 2439d5b72deSLars Poeschel gamsg->risefall = 0x00; 2449d5b72deSLars Poeschel gamsg->answer = 0x00; 2459d5b72deSLars Poeschel gamsg->__fill = 0x00; 2469d5b72deSLars Poeschel 2479d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 2489d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 2499d5b72deSLars Poeschel 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 2509d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 2519d5b72deSLars Poeschel 2529d5b72deSLars Poeschel mutex_unlock(&vb->lock); 2539d5b72deSLars Poeschel 2549d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpioa_msg)) 2559d5b72deSLars Poeschel return -EREMOTEIO; 2569d5b72deSLars Poeschel 2579d5b72deSLars Poeschel return 0; 2589d5b72deSLars Poeschel } 2599d5b72deSLars Poeschel 2609d5b72deSLars Poeschel /* ----- end of gpio a chip ---------------------------------------------- */ 2619d5b72deSLars Poeschel 2629d5b72deSLars Poeschel /* ----- begin of gipo b chip -------------------------------------------- */ 2639d5b72deSLars Poeschel 2649d5b72deSLars Poeschel static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset, 2659d5b72deSLars Poeschel unsigned dir) 2669d5b72deSLars Poeschel { 2679d5b72deSLars Poeschel struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 2689d5b72deSLars Poeschel int ret; 2699d5b72deSLars Poeschel 2709d5b72deSLars Poeschel gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR; 2719d5b72deSLars Poeschel gbmsg->val = cpu_to_be16(dir << offset); 2729d5b72deSLars Poeschel gbmsg->mask = cpu_to_be16(0x0001 << offset); 2739d5b72deSLars Poeschel 2749d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 2759d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000, 2769d5b72deSLars Poeschel 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), 2779d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 2789d5b72deSLars Poeschel 2799d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpiob_msg)) 2809d5b72deSLars Poeschel return -EREMOTEIO; 2819d5b72deSLars Poeschel 2829d5b72deSLars Poeschel return 0; 2839d5b72deSLars Poeschel } 2849d5b72deSLars Poeschel 2859d5b72deSLars Poeschel static int vprbrd_gpiob_get(struct gpio_chip *chip, 2869d5b72deSLars Poeschel unsigned offset) 2879d5b72deSLars Poeschel { 2889d5b72deSLars Poeschel int ret; 2899d5b72deSLars Poeschel u16 val; 2909d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 2919d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpiob); 2929d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 2939d5b72deSLars Poeschel struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 2949d5b72deSLars Poeschel 2959d5b72deSLars Poeschel /* if io is set to output, just return the saved value */ 2969d5b72deSLars Poeschel if (gpio->gpiob_out & (1 << offset)) 2979d5b72deSLars Poeschel return gpio->gpiob_val & (1 << offset); 2989d5b72deSLars Poeschel 2999d5b72deSLars Poeschel mutex_lock(&vb->lock); 3009d5b72deSLars Poeschel 3019d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), 3029d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000, 3039d5b72deSLars Poeschel 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), 3049d5b72deSLars Poeschel VPRBRD_USB_TIMEOUT_MS); 3059d5b72deSLars Poeschel val = gbmsg->val; 3069d5b72deSLars Poeschel 3079d5b72deSLars Poeschel mutex_unlock(&vb->lock); 3089d5b72deSLars Poeschel 3099d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpiob_msg)) 3109d5b72deSLars Poeschel return ret; 3119d5b72deSLars Poeschel 3129d5b72deSLars Poeschel /* cache the read values */ 3139d5b72deSLars Poeschel gpio->gpiob_val = be16_to_cpu(val); 3149d5b72deSLars Poeschel 3159d5b72deSLars Poeschel return (gpio->gpiob_val >> offset) & 0x1; 3169d5b72deSLars Poeschel } 3179d5b72deSLars Poeschel 3189d5b72deSLars Poeschel static void vprbrd_gpiob_set(struct gpio_chip *chip, 3199d5b72deSLars Poeschel unsigned offset, int value) 3209d5b72deSLars Poeschel { 3219d5b72deSLars Poeschel int ret; 3229d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 3239d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpiob); 3249d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 3259d5b72deSLars Poeschel struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 3269d5b72deSLars Poeschel 3279d5b72deSLars Poeschel if (gpio->gpiob_out & (1 << offset)) { 3289d5b72deSLars Poeschel if (value) 3299d5b72deSLars Poeschel gpio->gpiob_val |= (1 << offset); 3309d5b72deSLars Poeschel else 3319d5b72deSLars Poeschel gpio->gpiob_val &= ~(1 << offset); 3329d5b72deSLars Poeschel 3339d5b72deSLars Poeschel mutex_lock(&vb->lock); 3349d5b72deSLars Poeschel 3359d5b72deSLars Poeschel gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL; 3369d5b72deSLars Poeschel gbmsg->val = cpu_to_be16(value << offset); 3379d5b72deSLars Poeschel gbmsg->mask = cpu_to_be16(0x0001 << offset); 3389d5b72deSLars Poeschel 3399d5b72deSLars Poeschel ret = usb_control_msg(vb->usb_dev, 3409d5b72deSLars Poeschel usb_sndctrlpipe(vb->usb_dev, 0), 3419d5b72deSLars Poeschel VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 3429d5b72deSLars Poeschel 0x0000, 0x0000, gbmsg, 3439d5b72deSLars Poeschel sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS); 3449d5b72deSLars Poeschel 3459d5b72deSLars Poeschel mutex_unlock(&vb->lock); 3469d5b72deSLars Poeschel 3479d5b72deSLars Poeschel if (ret != sizeof(struct vprbrd_gpiob_msg)) 34858383c78SLinus Walleij dev_err(chip->parent, "usb error setting pin value\n"); 3499d5b72deSLars Poeschel } 3509d5b72deSLars Poeschel } 3519d5b72deSLars Poeschel 3529d5b72deSLars Poeschel static int vprbrd_gpiob_direction_input(struct gpio_chip *chip, 3539d5b72deSLars Poeschel unsigned offset) 3549d5b72deSLars Poeschel { 3559d5b72deSLars Poeschel int ret; 3569d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 3579d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpiob); 3589d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 3599d5b72deSLars Poeschel 3609d5b72deSLars Poeschel gpio->gpiob_out &= ~(1 << offset); 3619d5b72deSLars Poeschel 3629d5b72deSLars Poeschel mutex_lock(&vb->lock); 3639d5b72deSLars Poeschel 3649d5b72deSLars Poeschel ret = vprbrd_gpiob_setdir(vb, offset, 0); 3659d5b72deSLars Poeschel 3669d5b72deSLars Poeschel mutex_unlock(&vb->lock); 3679d5b72deSLars Poeschel 3689d5b72deSLars Poeschel if (ret) 36958383c78SLinus Walleij dev_err(chip->parent, "usb error setting pin to input\n"); 3709d5b72deSLars Poeschel 3719d5b72deSLars Poeschel return ret; 3729d5b72deSLars Poeschel } 3739d5b72deSLars Poeschel 3749d5b72deSLars Poeschel static int vprbrd_gpiob_direction_output(struct gpio_chip *chip, 3759d5b72deSLars Poeschel unsigned offset, int value) 3769d5b72deSLars Poeschel { 3779d5b72deSLars Poeschel int ret; 3789d5b72deSLars Poeschel struct vprbrd_gpio *gpio = 3799d5b72deSLars Poeschel container_of(chip, struct vprbrd_gpio, gpiob); 3809d5b72deSLars Poeschel struct vprbrd *vb = gpio->vb; 3819d5b72deSLars Poeschel 3829d5b72deSLars Poeschel gpio->gpiob_out |= (1 << offset); 3839d5b72deSLars Poeschel 3849d5b72deSLars Poeschel mutex_lock(&vb->lock); 3859d5b72deSLars Poeschel 3869d5b72deSLars Poeschel ret = vprbrd_gpiob_setdir(vb, offset, 1); 3879d5b72deSLars Poeschel if (ret) 38858383c78SLinus Walleij dev_err(chip->parent, "usb error setting pin to output\n"); 3899d5b72deSLars Poeschel 3909d5b72deSLars Poeschel mutex_unlock(&vb->lock); 3919d5b72deSLars Poeschel 3929d5b72deSLars Poeschel vprbrd_gpiob_set(chip, offset, value); 3939d5b72deSLars Poeschel 3949d5b72deSLars Poeschel return ret; 3959d5b72deSLars Poeschel } 3969d5b72deSLars Poeschel 3979d5b72deSLars Poeschel /* ----- end of gpio b chip ---------------------------------------------- */ 3989d5b72deSLars Poeschel 3990fe763c5SGreg Kroah-Hartman static int vprbrd_gpio_probe(struct platform_device *pdev) 4009d5b72deSLars Poeschel { 4019d5b72deSLars Poeschel struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); 4029d5b72deSLars Poeschel struct vprbrd_gpio *vb_gpio; 4039d5b72deSLars Poeschel int ret; 4049d5b72deSLars Poeschel 4059d5b72deSLars Poeschel vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL); 4069d5b72deSLars Poeschel if (vb_gpio == NULL) 4079d5b72deSLars Poeschel return -ENOMEM; 4089d5b72deSLars Poeschel 4099d5b72deSLars Poeschel vb_gpio->vb = vb; 4109d5b72deSLars Poeschel /* registering gpio a */ 4119d5b72deSLars Poeschel vb_gpio->gpioa.label = "viperboard gpio a"; 41258383c78SLinus Walleij vb_gpio->gpioa.parent = &pdev->dev; 4139d5b72deSLars Poeschel vb_gpio->gpioa.owner = THIS_MODULE; 4149d5b72deSLars Poeschel vb_gpio->gpioa.base = -1; 4159d5b72deSLars Poeschel vb_gpio->gpioa.ngpio = 16; 4169fb1f39eSLinus Walleij vb_gpio->gpioa.can_sleep = true; 4179d5b72deSLars Poeschel vb_gpio->gpioa.set = vprbrd_gpioa_set; 4189d5b72deSLars Poeschel vb_gpio->gpioa.get = vprbrd_gpioa_get; 4199d5b72deSLars Poeschel vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; 4209d5b72deSLars Poeschel vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output; 4219d5b72deSLars Poeschel ret = gpiochip_add(&vb_gpio->gpioa); 4229d5b72deSLars Poeschel if (ret < 0) { 42358383c78SLinus Walleij dev_err(vb_gpio->gpioa.parent, "could not add gpio a"); 4249d5b72deSLars Poeschel goto err_gpioa; 4259d5b72deSLars Poeschel } 4269d5b72deSLars Poeschel 4279d5b72deSLars Poeschel /* registering gpio b */ 4289d5b72deSLars Poeschel vb_gpio->gpiob.label = "viperboard gpio b"; 42958383c78SLinus Walleij vb_gpio->gpiob.parent = &pdev->dev; 4309d5b72deSLars Poeschel vb_gpio->gpiob.owner = THIS_MODULE; 4319d5b72deSLars Poeschel vb_gpio->gpiob.base = -1; 4329d5b72deSLars Poeschel vb_gpio->gpiob.ngpio = 16; 4339fb1f39eSLinus Walleij vb_gpio->gpiob.can_sleep = true; 4349d5b72deSLars Poeschel vb_gpio->gpiob.set = vprbrd_gpiob_set; 4359d5b72deSLars Poeschel vb_gpio->gpiob.get = vprbrd_gpiob_get; 4369d5b72deSLars Poeschel vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; 4379d5b72deSLars Poeschel vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output; 4389d5b72deSLars Poeschel ret = gpiochip_add(&vb_gpio->gpiob); 4399d5b72deSLars Poeschel if (ret < 0) { 44058383c78SLinus Walleij dev_err(vb_gpio->gpiob.parent, "could not add gpio b"); 4419d5b72deSLars Poeschel goto err_gpiob; 4429d5b72deSLars Poeschel } 4439d5b72deSLars Poeschel 4449d5b72deSLars Poeschel platform_set_drvdata(pdev, vb_gpio); 4459d5b72deSLars Poeschel 4469d5b72deSLars Poeschel return ret; 4479d5b72deSLars Poeschel 4489d5b72deSLars Poeschel err_gpiob: 4499f5132aeSabdoulaye berthe gpiochip_remove(&vb_gpio->gpioa); 4509d5b72deSLars Poeschel 4519d5b72deSLars Poeschel err_gpioa: 4529d5b72deSLars Poeschel return ret; 4539d5b72deSLars Poeschel } 4549d5b72deSLars Poeschel 4550fe763c5SGreg Kroah-Hartman static int vprbrd_gpio_remove(struct platform_device *pdev) 4569d5b72deSLars Poeschel { 4579d5b72deSLars Poeschel struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev); 4589d5b72deSLars Poeschel 4599f5132aeSabdoulaye berthe gpiochip_remove(&vb_gpio->gpiob); 4609d5b72deSLars Poeschel 4619f5132aeSabdoulaye berthe return 0; 4629d5b72deSLars Poeschel } 4639d5b72deSLars Poeschel 4649d5b72deSLars Poeschel static struct platform_driver vprbrd_gpio_driver = { 4659d5b72deSLars Poeschel .driver.name = "viperboard-gpio", 4669d5b72deSLars Poeschel .driver.owner = THIS_MODULE, 4679d5b72deSLars Poeschel .probe = vprbrd_gpio_probe, 4680fe763c5SGreg Kroah-Hartman .remove = vprbrd_gpio_remove, 4699d5b72deSLars Poeschel }; 4709d5b72deSLars Poeschel 4719d5b72deSLars Poeschel static int __init vprbrd_gpio_init(void) 4729d5b72deSLars Poeschel { 4739d5b72deSLars Poeschel switch (gpioa_freq) { 4749d5b72deSLars Poeschel case 1000000: 4759d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ; 4769d5b72deSLars Poeschel break; 4779d5b72deSLars Poeschel case 100000: 4789d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ; 4799d5b72deSLars Poeschel break; 4809d5b72deSLars Poeschel case 10000: 4819d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ; 4829d5b72deSLars Poeschel break; 4839d5b72deSLars Poeschel case 1000: 4849d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; 4859d5b72deSLars Poeschel break; 4869d5b72deSLars Poeschel case 100: 4879d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_100HZ; 4889d5b72deSLars Poeschel break; 4899d5b72deSLars Poeschel case 10: 4909d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_10HZ; 4919d5b72deSLars Poeschel break; 4929d5b72deSLars Poeschel default: 4939d5b72deSLars Poeschel pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq); 4949d5b72deSLars Poeschel gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; 4959d5b72deSLars Poeschel } 4969d5b72deSLars Poeschel 4979d5b72deSLars Poeschel return platform_driver_register(&vprbrd_gpio_driver); 4989d5b72deSLars Poeschel } 4999d5b72deSLars Poeschel subsys_initcall(vprbrd_gpio_init); 5009d5b72deSLars Poeschel 5019d5b72deSLars Poeschel static void __exit vprbrd_gpio_exit(void) 5029d5b72deSLars Poeschel { 5039d5b72deSLars Poeschel platform_driver_unregister(&vprbrd_gpio_driver); 5049d5b72deSLars Poeschel } 5059d5b72deSLars Poeschel module_exit(vprbrd_gpio_exit); 5069d5b72deSLars Poeschel 5079d5b72deSLars Poeschel MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); 5089d5b72deSLars Poeschel MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard"); 5099d5b72deSLars Poeschel MODULE_LICENSE("GPL"); 5109d5b72deSLars Poeschel MODULE_ALIAS("platform:viperboard-gpio"); 511