162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Nano River Technologies viperboard GPIO lib driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) 2012 by Lemonage GmbH 662306a36Sopenharmony_ci * Author: Lars Poeschel <poeschel@lemonage.de> 762306a36Sopenharmony_ci * All rights reserved. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/usb.h> 1862306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/mfd/viperboard.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_1MHZ 0 2362306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_100KHZ 1 2462306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_10KHZ 2 2562306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_1KHZ 3 2662306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_100HZ 4 2762306a36Sopenharmony_ci#define VPRBRD_GPIOA_CLK_10HZ 5 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define VPRBRD_GPIOA_FREQ_DEFAULT 1000 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_CONT 0x00 3262306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_PULSE 0x01 3362306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_PWM 0x02 3462306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_SETOUT 0x03 3562306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_SETIN 0x04 3662306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_SETINT 0x05 3762306a36Sopenharmony_ci#define VPRBRD_GPIOA_CMD_GETIN 0x06 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define VPRBRD_GPIOB_CMD_SETDIR 0x00 4062306a36Sopenharmony_ci#define VPRBRD_GPIOB_CMD_SETVAL 0x01 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct vprbrd_gpioa_msg { 4362306a36Sopenharmony_ci u8 cmd; 4462306a36Sopenharmony_ci u8 clk; 4562306a36Sopenharmony_ci u8 offset; 4662306a36Sopenharmony_ci u8 t1; 4762306a36Sopenharmony_ci u8 t2; 4862306a36Sopenharmony_ci u8 invert; 4962306a36Sopenharmony_ci u8 pwmlevel; 5062306a36Sopenharmony_ci u8 outval; 5162306a36Sopenharmony_ci u8 risefall; 5262306a36Sopenharmony_ci u8 answer; 5362306a36Sopenharmony_ci u8 __fill; 5462306a36Sopenharmony_ci} __packed; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct vprbrd_gpiob_msg { 5762306a36Sopenharmony_ci u8 cmd; 5862306a36Sopenharmony_ci u16 val; 5962306a36Sopenharmony_ci u16 mask; 6062306a36Sopenharmony_ci} __packed; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistruct vprbrd_gpio { 6362306a36Sopenharmony_ci struct gpio_chip gpioa; /* gpio a related things */ 6462306a36Sopenharmony_ci u32 gpioa_out; 6562306a36Sopenharmony_ci u32 gpioa_val; 6662306a36Sopenharmony_ci struct gpio_chip gpiob; /* gpio b related things */ 6762306a36Sopenharmony_ci u32 gpiob_out; 6862306a36Sopenharmony_ci u32 gpiob_val; 6962306a36Sopenharmony_ci struct vprbrd *vb; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* gpioa sampling clock module parameter */ 7362306a36Sopenharmony_cistatic unsigned char gpioa_clk; 7462306a36Sopenharmony_cistatic unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT; 7562306a36Sopenharmony_cimodule_param(gpioa_freq, uint, 0); 7662306a36Sopenharmony_ciMODULE_PARM_DESC(gpioa_freq, 7762306a36Sopenharmony_ci "gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* ----- begin of gipo a chip -------------------------------------------- */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int vprbrd_gpioa_get(struct gpio_chip *chip, 8262306a36Sopenharmony_ci unsigned int offset) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int ret, answer, error = 0; 8562306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 8662306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 8762306a36Sopenharmony_ci struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* if io is set to output, just return the saved value */ 9062306a36Sopenharmony_ci if (gpio->gpioa_out & (1 << offset)) 9162306a36Sopenharmony_ci return !!(gpio->gpioa_val & (1 << offset)); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci mutex_lock(&vb->lock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN; 9662306a36Sopenharmony_ci gamsg->clk = 0x00; 9762306a36Sopenharmony_ci gamsg->offset = offset; 9862306a36Sopenharmony_ci gamsg->t1 = 0x00; 9962306a36Sopenharmony_ci gamsg->t2 = 0x00; 10062306a36Sopenharmony_ci gamsg->invert = 0x00; 10162306a36Sopenharmony_ci gamsg->pwmlevel = 0x00; 10262306a36Sopenharmony_ci gamsg->outval = 0x00; 10362306a36Sopenharmony_ci gamsg->risefall = 0x00; 10462306a36Sopenharmony_ci gamsg->answer = 0x00; 10562306a36Sopenharmony_ci gamsg->__fill = 0x00; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 10862306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 10962306a36Sopenharmony_ci 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 11062306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 11162306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpioa_msg)) 11262306a36Sopenharmony_ci error = -EREMOTEIO; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), 11562306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000, 11662306a36Sopenharmony_ci 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 11762306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 11862306a36Sopenharmony_ci answer = gamsg->answer & 0x01; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci mutex_unlock(&vb->lock); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpioa_msg)) 12362306a36Sopenharmony_ci error = -EREMOTEIO; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (error) 12662306a36Sopenharmony_ci return error; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return answer; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void vprbrd_gpioa_set(struct gpio_chip *chip, 13262306a36Sopenharmony_ci unsigned int offset, int value) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int ret; 13562306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 13662306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 13762306a36Sopenharmony_ci struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (gpio->gpioa_out & (1 << offset)) { 14062306a36Sopenharmony_ci if (value) 14162306a36Sopenharmony_ci gpio->gpioa_val |= (1 << offset); 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci gpio->gpioa_val &= ~(1 << offset); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci mutex_lock(&vb->lock); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; 14862306a36Sopenharmony_ci gamsg->clk = 0x00; 14962306a36Sopenharmony_ci gamsg->offset = offset; 15062306a36Sopenharmony_ci gamsg->t1 = 0x00; 15162306a36Sopenharmony_ci gamsg->t2 = 0x00; 15262306a36Sopenharmony_ci gamsg->invert = 0x00; 15362306a36Sopenharmony_ci gamsg->pwmlevel = 0x00; 15462306a36Sopenharmony_ci gamsg->outval = value; 15562306a36Sopenharmony_ci gamsg->risefall = 0x00; 15662306a36Sopenharmony_ci gamsg->answer = 0x00; 15762306a36Sopenharmony_ci gamsg->__fill = 0x00; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, 16062306a36Sopenharmony_ci usb_sndctrlpipe(vb->usb_dev, 0), 16162306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 16262306a36Sopenharmony_ci 0x0000, 0x0000, gamsg, 16362306a36Sopenharmony_ci sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci mutex_unlock(&vb->lock); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpioa_msg)) 16862306a36Sopenharmony_ci dev_err(chip->parent, "usb error setting pin value\n"); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int vprbrd_gpioa_direction_input(struct gpio_chip *chip, 17362306a36Sopenharmony_ci unsigned int offset) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci int ret; 17662306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 17762306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 17862306a36Sopenharmony_ci struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci gpio->gpioa_out &= ~(1 << offset); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci mutex_lock(&vb->lock); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN; 18562306a36Sopenharmony_ci gamsg->clk = gpioa_clk; 18662306a36Sopenharmony_ci gamsg->offset = offset; 18762306a36Sopenharmony_ci gamsg->t1 = 0x00; 18862306a36Sopenharmony_ci gamsg->t2 = 0x00; 18962306a36Sopenharmony_ci gamsg->invert = 0x00; 19062306a36Sopenharmony_ci gamsg->pwmlevel = 0x00; 19162306a36Sopenharmony_ci gamsg->outval = 0x00; 19262306a36Sopenharmony_ci gamsg->risefall = 0x00; 19362306a36Sopenharmony_ci gamsg->answer = 0x00; 19462306a36Sopenharmony_ci gamsg->__fill = 0x00; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 19762306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 19862306a36Sopenharmony_ci 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 19962306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci mutex_unlock(&vb->lock); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpioa_msg)) 20462306a36Sopenharmony_ci return -EREMOTEIO; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int vprbrd_gpioa_direction_output(struct gpio_chip *chip, 21062306a36Sopenharmony_ci unsigned int offset, int value) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci int ret; 21362306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 21462306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 21562306a36Sopenharmony_ci struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci gpio->gpioa_out |= (1 << offset); 21862306a36Sopenharmony_ci if (value) 21962306a36Sopenharmony_ci gpio->gpioa_val |= (1 << offset); 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci gpio->gpioa_val &= ~(1 << offset); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci mutex_lock(&vb->lock); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; 22662306a36Sopenharmony_ci gamsg->clk = 0x00; 22762306a36Sopenharmony_ci gamsg->offset = offset; 22862306a36Sopenharmony_ci gamsg->t1 = 0x00; 22962306a36Sopenharmony_ci gamsg->t2 = 0x00; 23062306a36Sopenharmony_ci gamsg->invert = 0x00; 23162306a36Sopenharmony_ci gamsg->pwmlevel = 0x00; 23262306a36Sopenharmony_ci gamsg->outval = value; 23362306a36Sopenharmony_ci gamsg->risefall = 0x00; 23462306a36Sopenharmony_ci gamsg->answer = 0x00; 23562306a36Sopenharmony_ci gamsg->__fill = 0x00; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 23862306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, 23962306a36Sopenharmony_ci 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), 24062306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci mutex_unlock(&vb->lock); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpioa_msg)) 24562306a36Sopenharmony_ci return -EREMOTEIO; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* ----- end of gpio a chip ---------------------------------------------- */ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* ----- begin of gipo b chip -------------------------------------------- */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset, 25562306a36Sopenharmony_ci unsigned int dir) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 25862306a36Sopenharmony_ci int ret; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR; 26162306a36Sopenharmony_ci gbmsg->val = cpu_to_be16(dir << offset); 26262306a36Sopenharmony_ci gbmsg->mask = cpu_to_be16(0x0001 << offset); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), 26562306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000, 26662306a36Sopenharmony_ci 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), 26762306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpiob_msg)) 27062306a36Sopenharmony_ci return -EREMOTEIO; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int vprbrd_gpiob_get(struct gpio_chip *chip, 27662306a36Sopenharmony_ci unsigned int offset) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int ret; 27962306a36Sopenharmony_ci u16 val; 28062306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 28162306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 28262306a36Sopenharmony_ci struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* if io is set to output, just return the saved value */ 28562306a36Sopenharmony_ci if (gpio->gpiob_out & (1 << offset)) 28662306a36Sopenharmony_ci return gpio->gpiob_val & (1 << offset); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci mutex_lock(&vb->lock); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), 29162306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000, 29262306a36Sopenharmony_ci 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), 29362306a36Sopenharmony_ci VPRBRD_USB_TIMEOUT_MS); 29462306a36Sopenharmony_ci val = gbmsg->val; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mutex_unlock(&vb->lock); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpiob_msg)) 29962306a36Sopenharmony_ci return ret; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* cache the read values */ 30262306a36Sopenharmony_ci gpio->gpiob_val = be16_to_cpu(val); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return (gpio->gpiob_val >> offset) & 0x1; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void vprbrd_gpiob_set(struct gpio_chip *chip, 30862306a36Sopenharmony_ci unsigned int offset, int value) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 31262306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 31362306a36Sopenharmony_ci struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (gpio->gpiob_out & (1 << offset)) { 31662306a36Sopenharmony_ci if (value) 31762306a36Sopenharmony_ci gpio->gpiob_val |= (1 << offset); 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci gpio->gpiob_val &= ~(1 << offset); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci mutex_lock(&vb->lock); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL; 32462306a36Sopenharmony_ci gbmsg->val = cpu_to_be16(value << offset); 32562306a36Sopenharmony_ci gbmsg->mask = cpu_to_be16(0x0001 << offset); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ret = usb_control_msg(vb->usb_dev, 32862306a36Sopenharmony_ci usb_sndctrlpipe(vb->usb_dev, 0), 32962306a36Sopenharmony_ci VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 33062306a36Sopenharmony_ci 0x0000, 0x0000, gbmsg, 33162306a36Sopenharmony_ci sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci mutex_unlock(&vb->lock); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (ret != sizeof(struct vprbrd_gpiob_msg)) 33662306a36Sopenharmony_ci dev_err(chip->parent, "usb error setting pin value\n"); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int vprbrd_gpiob_direction_input(struct gpio_chip *chip, 34162306a36Sopenharmony_ci unsigned int offset) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci int ret; 34462306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 34562306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci gpio->gpiob_out &= ~(1 << offset); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci mutex_lock(&vb->lock); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ret = vprbrd_gpiob_setdir(vb, offset, 0); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci mutex_unlock(&vb->lock); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (ret) 35662306a36Sopenharmony_ci dev_err(chip->parent, "usb error setting pin to input\n"); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return ret; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int vprbrd_gpiob_direction_output(struct gpio_chip *chip, 36262306a36Sopenharmony_ci unsigned int offset, int value) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci int ret; 36562306a36Sopenharmony_ci struct vprbrd_gpio *gpio = gpiochip_get_data(chip); 36662306a36Sopenharmony_ci struct vprbrd *vb = gpio->vb; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci gpio->gpiob_out |= (1 << offset); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci mutex_lock(&vb->lock); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci ret = vprbrd_gpiob_setdir(vb, offset, 1); 37362306a36Sopenharmony_ci if (ret) 37462306a36Sopenharmony_ci dev_err(chip->parent, "usb error setting pin to output\n"); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci mutex_unlock(&vb->lock); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci vprbrd_gpiob_set(chip, offset, value); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return ret; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* ----- end of gpio b chip ---------------------------------------------- */ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int vprbrd_gpio_probe(struct platform_device *pdev) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); 38862306a36Sopenharmony_ci struct vprbrd_gpio *vb_gpio; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL); 39262306a36Sopenharmony_ci if (vb_gpio == NULL) 39362306a36Sopenharmony_ci return -ENOMEM; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci vb_gpio->vb = vb; 39662306a36Sopenharmony_ci /* registering gpio a */ 39762306a36Sopenharmony_ci vb_gpio->gpioa.label = "viperboard gpio a"; 39862306a36Sopenharmony_ci vb_gpio->gpioa.parent = &pdev->dev; 39962306a36Sopenharmony_ci vb_gpio->gpioa.owner = THIS_MODULE; 40062306a36Sopenharmony_ci vb_gpio->gpioa.base = -1; 40162306a36Sopenharmony_ci vb_gpio->gpioa.ngpio = 16; 40262306a36Sopenharmony_ci vb_gpio->gpioa.can_sleep = true; 40362306a36Sopenharmony_ci vb_gpio->gpioa.set = vprbrd_gpioa_set; 40462306a36Sopenharmony_ci vb_gpio->gpioa.get = vprbrd_gpioa_get; 40562306a36Sopenharmony_ci vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; 40662306a36Sopenharmony_ci vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpioa, vb_gpio); 40962306a36Sopenharmony_ci if (ret < 0) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* registering gpio b */ 41362306a36Sopenharmony_ci vb_gpio->gpiob.label = "viperboard gpio b"; 41462306a36Sopenharmony_ci vb_gpio->gpiob.parent = &pdev->dev; 41562306a36Sopenharmony_ci vb_gpio->gpiob.owner = THIS_MODULE; 41662306a36Sopenharmony_ci vb_gpio->gpiob.base = -1; 41762306a36Sopenharmony_ci vb_gpio->gpiob.ngpio = 16; 41862306a36Sopenharmony_ci vb_gpio->gpiob.can_sleep = true; 41962306a36Sopenharmony_ci vb_gpio->gpiob.set = vprbrd_gpiob_set; 42062306a36Sopenharmony_ci vb_gpio->gpiob.get = vprbrd_gpiob_get; 42162306a36Sopenharmony_ci vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; 42262306a36Sopenharmony_ci vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpiob, vb_gpio); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic struct platform_driver vprbrd_gpio_driver = { 42862306a36Sopenharmony_ci .driver.name = "viperboard-gpio", 42962306a36Sopenharmony_ci .probe = vprbrd_gpio_probe, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int __init vprbrd_gpio_init(void) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci switch (gpioa_freq) { 43562306a36Sopenharmony_ci case 1000000: 43662306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ; 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case 100000: 43962306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci case 10000: 44262306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ; 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci case 1000: 44562306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case 100: 44862306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_100HZ; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case 10: 45162306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_10HZ; 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci default: 45462306a36Sopenharmony_ci pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq); 45562306a36Sopenharmony_ci gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return platform_driver_register(&vprbrd_gpio_driver); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_cisubsys_initcall(vprbrd_gpio_init); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void __exit vprbrd_gpio_exit(void) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci platform_driver_unregister(&vprbrd_gpio_driver); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_cimodule_exit(vprbrd_gpio_exit); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ciMODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); 46962306a36Sopenharmony_ciMODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard"); 47062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 47162306a36Sopenharmony_ciMODULE_ALIAS("platform:viperboard-gpio"); 472