brintos

brintos / linux-shallow public Read only

0
0
Text · 11.7 KiB · e55d28a Raw
472 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 *  Nano River Technologies viperboard GPIO lib driver4 *5 *  (C) 2012 by Lemonage GmbH6 *  Author: Lars Poeschel <poeschel@lemonage.de>7 *  All rights reserved.8 */9 10#include <linux/kernel.h>11#include <linux/errno.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/types.h>15#include <linux/mutex.h>16#include <linux/platform_device.h>17#include <linux/usb.h>18#include <linux/gpio/driver.h>19 20#include <linux/mfd/viperboard.h>21 22#define VPRBRD_GPIOA_CLK_1MHZ		023#define VPRBRD_GPIOA_CLK_100KHZ		124#define VPRBRD_GPIOA_CLK_10KHZ		225#define VPRBRD_GPIOA_CLK_1KHZ		326#define VPRBRD_GPIOA_CLK_100HZ		427#define VPRBRD_GPIOA_CLK_10HZ		528 29#define VPRBRD_GPIOA_FREQ_DEFAULT	100030 31#define VPRBRD_GPIOA_CMD_CONT		0x0032#define VPRBRD_GPIOA_CMD_PULSE		0x0133#define VPRBRD_GPIOA_CMD_PWM		0x0234#define VPRBRD_GPIOA_CMD_SETOUT		0x0335#define VPRBRD_GPIOA_CMD_SETIN		0x0436#define VPRBRD_GPIOA_CMD_SETINT		0x0537#define VPRBRD_GPIOA_CMD_GETIN		0x0638 39#define VPRBRD_GPIOB_CMD_SETDIR		0x0040#define VPRBRD_GPIOB_CMD_SETVAL		0x0141 42struct vprbrd_gpioa_msg {43	u8 cmd;44	u8 clk;45	u8 offset;46	u8 t1;47	u8 t2;48	u8 invert;49	u8 pwmlevel;50	u8 outval;51	u8 risefall;52	u8 answer;53	u8 __fill;54} __packed;55 56struct vprbrd_gpiob_msg {57	u8 cmd;58	u16 val;59	u16 mask;60} __packed;61 62struct vprbrd_gpio {63	struct gpio_chip gpioa; /* gpio a related things */64	u32 gpioa_out;65	u32 gpioa_val;66	struct gpio_chip gpiob; /* gpio b related things */67	u32 gpiob_out;68	u32 gpiob_val;69	struct vprbrd *vb;70};71 72/* gpioa sampling clock module parameter */73static unsigned char gpioa_clk;74static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT;75module_param(gpioa_freq, uint, 0);76MODULE_PARM_DESC(gpioa_freq,77	"gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000");78 79/* ----- begin of gipo a chip -------------------------------------------- */80 81static int vprbrd_gpioa_get(struct gpio_chip *chip,82		unsigned int offset)83{84	int ret, answer, error = 0;85	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);86	struct vprbrd *vb = gpio->vb;87	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;88 89	/* if io is set to output, just return the saved value */90	if (gpio->gpioa_out & (1 << offset))91		return !!(gpio->gpioa_val & (1 << offset));92 93	mutex_lock(&vb->lock);94 95	gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN;96	gamsg->clk = 0x00;97	gamsg->offset = offset;98	gamsg->t1 = 0x00;99	gamsg->t2 = 0x00;100	gamsg->invert = 0x00;101	gamsg->pwmlevel = 0x00;102	gamsg->outval = 0x00;103	gamsg->risefall = 0x00;104	gamsg->answer = 0x00;105	gamsg->__fill = 0x00;106 107	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),108		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,109		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),110		VPRBRD_USB_TIMEOUT_MS);111	if (ret != sizeof(struct vprbrd_gpioa_msg))112		error = -EREMOTEIO;113 114	ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),115		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000,116		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),117		VPRBRD_USB_TIMEOUT_MS);118	answer = gamsg->answer & 0x01;119 120	mutex_unlock(&vb->lock);121 122	if (ret != sizeof(struct vprbrd_gpioa_msg))123		error = -EREMOTEIO;124 125	if (error)126		return error;127 128	return answer;129}130 131static void vprbrd_gpioa_set(struct gpio_chip *chip,132		unsigned int offset, int value)133{134	int ret;135	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);136	struct vprbrd *vb = gpio->vb;137	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;138 139	if (gpio->gpioa_out & (1 << offset)) {140		if (value)141			gpio->gpioa_val |= (1 << offset);142		else143			gpio->gpioa_val &= ~(1 << offset);144 145		mutex_lock(&vb->lock);146 147		gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;148		gamsg->clk = 0x00;149		gamsg->offset = offset;150		gamsg->t1 = 0x00;151		gamsg->t2 = 0x00;152		gamsg->invert = 0x00;153		gamsg->pwmlevel = 0x00;154		gamsg->outval = value;155		gamsg->risefall = 0x00;156		gamsg->answer = 0x00;157		gamsg->__fill = 0x00;158 159		ret = usb_control_msg(vb->usb_dev,160			usb_sndctrlpipe(vb->usb_dev, 0),161			VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT,162			0x0000,	0x0000, gamsg,163			sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS);164 165		mutex_unlock(&vb->lock);166 167		if (ret != sizeof(struct vprbrd_gpioa_msg))168			dev_err(chip->parent, "usb error setting pin value\n");169	}170}171 172static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,173			unsigned int offset)174{175	int ret;176	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);177	struct vprbrd *vb = gpio->vb;178	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;179 180	gpio->gpioa_out &= ~(1 << offset);181 182	mutex_lock(&vb->lock);183 184	gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN;185	gamsg->clk = gpioa_clk;186	gamsg->offset = offset;187	gamsg->t1 = 0x00;188	gamsg->t2 = 0x00;189	gamsg->invert = 0x00;190	gamsg->pwmlevel = 0x00;191	gamsg->outval = 0x00;192	gamsg->risefall = 0x00;193	gamsg->answer = 0x00;194	gamsg->__fill = 0x00;195 196	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),197		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,198		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),199		VPRBRD_USB_TIMEOUT_MS);200 201	mutex_unlock(&vb->lock);202 203	if (ret != sizeof(struct vprbrd_gpioa_msg))204		return -EREMOTEIO;205 206	return 0;207}208 209static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,210			unsigned int offset, int value)211{212	int ret;213	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);214	struct vprbrd *vb = gpio->vb;215	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;216 217	gpio->gpioa_out |= (1 << offset);218	if (value)219		gpio->gpioa_val |= (1 << offset);220	else221		gpio->gpioa_val &= ~(1 << offset);222 223	mutex_lock(&vb->lock);224 225	gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;226	gamsg->clk = 0x00;227	gamsg->offset = offset;228	gamsg->t1 = 0x00;229	gamsg->t2 = 0x00;230	gamsg->invert = 0x00;231	gamsg->pwmlevel = 0x00;232	gamsg->outval = value;233	gamsg->risefall = 0x00;234	gamsg->answer = 0x00;235	gamsg->__fill = 0x00;236 237	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),238		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,239		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),240		VPRBRD_USB_TIMEOUT_MS);241 242	mutex_unlock(&vb->lock);243 244	if (ret != sizeof(struct vprbrd_gpioa_msg))245		return -EREMOTEIO;246 247	return 0;248}249 250/* ----- end of gpio a chip ---------------------------------------------- */251 252/* ----- begin of gipo b chip -------------------------------------------- */253 254static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,255	unsigned int dir)256{257	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;258	int ret;259 260	gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR;261	gbmsg->val = cpu_to_be16(dir << offset);262	gbmsg->mask = cpu_to_be16(0x0001 << offset);263 264	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),265		VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000,266		0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg),267		VPRBRD_USB_TIMEOUT_MS);268 269	if (ret != sizeof(struct vprbrd_gpiob_msg))270		return -EREMOTEIO;271 272	return 0;273}274 275static int vprbrd_gpiob_get(struct gpio_chip *chip,276		unsigned int offset)277{278	int ret;279	u16 val;280	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);281	struct vprbrd *vb = gpio->vb;282	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;283 284	/* if io is set to output, just return the saved value */285	if (gpio->gpiob_out & (1 << offset))286		return gpio->gpiob_val & (1 << offset);287 288	mutex_lock(&vb->lock);289 290	ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),291		VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000,292		0x0000, gbmsg,	sizeof(struct vprbrd_gpiob_msg),293		VPRBRD_USB_TIMEOUT_MS);294	val = gbmsg->val;295 296	mutex_unlock(&vb->lock);297 298	if (ret != sizeof(struct vprbrd_gpiob_msg))299		return ret;300 301	/* cache the read values */302	gpio->gpiob_val = be16_to_cpu(val);303 304	return (gpio->gpiob_val >> offset) & 0x1;305}306 307static void vprbrd_gpiob_set(struct gpio_chip *chip,308		unsigned int offset, int value)309{310	int ret;311	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);312	struct vprbrd *vb = gpio->vb;313	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;314 315	if (gpio->gpiob_out & (1 << offset)) {316		if (value)317			gpio->gpiob_val |= (1 << offset);318		else319			gpio->gpiob_val &= ~(1 << offset);320 321		mutex_lock(&vb->lock);322 323		gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL;324		gbmsg->val = cpu_to_be16(value << offset);325		gbmsg->mask = cpu_to_be16(0x0001 << offset);326 327		ret = usb_control_msg(vb->usb_dev,328			usb_sndctrlpipe(vb->usb_dev, 0),329			VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT,330			0x0000,	0x0000, gbmsg,331			sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS);332 333		mutex_unlock(&vb->lock);334 335		if (ret != sizeof(struct vprbrd_gpiob_msg))336			dev_err(chip->parent, "usb error setting pin value\n");337	}338}339 340static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,341			unsigned int offset)342{343	int ret;344	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);345	struct vprbrd *vb = gpio->vb;346 347	gpio->gpiob_out &= ~(1 << offset);348 349	mutex_lock(&vb->lock);350 351	ret = vprbrd_gpiob_setdir(vb, offset, 0);352 353	mutex_unlock(&vb->lock);354 355	if (ret)356		dev_err(chip->parent, "usb error setting pin to input\n");357 358	return ret;359}360 361static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,362			unsigned int offset, int value)363{364	int ret;365	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);366	struct vprbrd *vb = gpio->vb;367 368	gpio->gpiob_out |= (1 << offset);369 370	mutex_lock(&vb->lock);371 372	ret = vprbrd_gpiob_setdir(vb, offset, 1);373	if (ret)374		dev_err(chip->parent, "usb error setting pin to output\n");375 376	mutex_unlock(&vb->lock);377 378	vprbrd_gpiob_set(chip, offset, value);379 380	return ret;381}382 383/* ----- end of gpio b chip ---------------------------------------------- */384 385static int vprbrd_gpio_probe(struct platform_device *pdev)386{387	struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);388	struct vprbrd_gpio *vb_gpio;389	int ret;390 391	vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL);392	if (vb_gpio == NULL)393		return -ENOMEM;394 395	vb_gpio->vb = vb;396	/* registering gpio a */397	vb_gpio->gpioa.label = "viperboard gpio a";398	vb_gpio->gpioa.parent = &pdev->dev;399	vb_gpio->gpioa.owner = THIS_MODULE;400	vb_gpio->gpioa.base = -1;401	vb_gpio->gpioa.ngpio = 16;402	vb_gpio->gpioa.can_sleep = true;403	vb_gpio->gpioa.set = vprbrd_gpioa_set;404	vb_gpio->gpioa.get = vprbrd_gpioa_get;405	vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;406	vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;407 408	ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpioa, vb_gpio);409	if (ret < 0)410		return ret;411 412	/* registering gpio b */413	vb_gpio->gpiob.label = "viperboard gpio b";414	vb_gpio->gpiob.parent = &pdev->dev;415	vb_gpio->gpiob.owner = THIS_MODULE;416	vb_gpio->gpiob.base = -1;417	vb_gpio->gpiob.ngpio = 16;418	vb_gpio->gpiob.can_sleep = true;419	vb_gpio->gpiob.set = vprbrd_gpiob_set;420	vb_gpio->gpiob.get = vprbrd_gpiob_get;421	vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;422	vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;423 424	return devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpiob, vb_gpio);425}426 427static struct platform_driver vprbrd_gpio_driver = {428	.driver.name	= "viperboard-gpio",429	.probe		= vprbrd_gpio_probe,430};431 432static int __init vprbrd_gpio_init(void)433{434	switch (gpioa_freq) {435	case 1000000:436		gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ;437		break;438	case 100000:439		gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ;440		break;441	case 10000:442		gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ;443		break;444	case 1000:445		gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;446		break;447	case 100:448		gpioa_clk = VPRBRD_GPIOA_CLK_100HZ;449		break;450	case 10:451		gpioa_clk = VPRBRD_GPIOA_CLK_10HZ;452		break;453	default:454		pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq);455		gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;456	}457 458	return platform_driver_register(&vprbrd_gpio_driver);459}460subsys_initcall(vprbrd_gpio_init);461 462static void __exit vprbrd_gpio_exit(void)463{464	platform_driver_unregister(&vprbrd_gpio_driver);465}466module_exit(vprbrd_gpio_exit);467 468MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");469MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard");470MODULE_LICENSE("GPL");471MODULE_ALIAS("platform:viperboard-gpio");472