1/* 2 * Custom GPIO-based rotary driver 3 * 4 * Copyright (C) 2010 Claudio Mignanti <c.mignanti@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Strongly based on Custom GPIO-based I2C driver by: 11 * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> 12 * 13 * --------------------------------------------------------------------------- 14 * 15 * The behaviour of this driver can be altered by setting some parameters 16 * from the insmod command line. 17 * 18 * The following parameters are adjustable: 19 * 20 * bus0 These four arguments can be arrays of 21 * bus1 1-8 unsigned integers as follows: 22 * bus2 23 * bus3 <id>,<steps>,<axis>,<gpioa>,<gpiob>,<inverted> 24 * 25 * 26 * If this driver is built into the kernel, you can use the following kernel 27 * command line parameters, with the same values as the corresponding module 28 * parameters listed above: 29 * 30 * rotary-gpio-custom.bus0 31 * rotary-gpio-custom.bus1 32 * rotary-gpio-custom.bus2 33 * rotary-gpio-custom.bus3 34 */ 35 36#include <linux/kernel.h> 37#include <linux/module.h> 38#include <linux/init.h> 39#include <linux/input.h> 40#include <linux/platform_device.h> 41#include <linux/rotary_encoder.h> 42 43#define DRV_NAME "rotary-gpio-custom" 44#define DRV_DESC "Custom GPIO-based rotary driver" 45#define DRV_VERSION "0.1.0" 46 47#define PFX DRV_NAME ": " 48 49#define BUS_PARAM_REQUIRED 5 50#define BUS_PARAM_COUNT 6 51#define BUS_COUNT_MAX 4 52 53static unsigned int bus0[BUS_PARAM_COUNT] __initdata; 54static unsigned int bus1[BUS_PARAM_COUNT] __initdata; 55static unsigned int bus2[BUS_PARAM_COUNT] __initdata; 56static unsigned int bus3[BUS_PARAM_COUNT] __initdata; 57 58static unsigned int bus_nump[BUS_COUNT_MAX] __initdata; 59 60#define BUS_PARM_DESC \ 61 " config -> id,steps,axis,gpioa,gpiob[,inverted]" 62 63module_param_array(bus0, uint, &bus_nump[0], 0); 64MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC); 65module_param_array(bus1, uint, &bus_nump[1], 0); 66MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC); 67module_param_array(bus2, uint, &bus_nump[2], 0); 68MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC); 69module_param_array(bus3, uint, &bus_nump[3], 0); 70MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC); 71 72static struct platform_device *devices[BUS_COUNT_MAX]; 73static unsigned int nr_devices; 74 75static void rotary_gpio_custom_cleanup(void) 76{ 77 int i; 78 79 for (i = 0; i < nr_devices; i++) 80 if (devices[i]) 81 platform_device_put(devices[i]); 82} 83 84static int __init rotary_gpio_custom_add_one(unsigned int id, 85 unsigned int *params) 86{ 87 struct platform_device *pdev; 88 struct rotary_encoder_platform_data pdata; 89 int err; 90 91 if (!bus_nump[id]) 92 return 0; 93 94 if (bus_nump[id] < BUS_PARAM_REQUIRED) { 95 printk(KERN_ERR PFX "not enough parameters for bus%d\n", id); 96 err = -EINVAL; 97 goto err; 98 } 99 100 pdev = platform_device_alloc("rotary-gpio", params[0]); 101 if (!pdev) { 102 err = -ENOMEM; 103 goto err; 104 } 105 106 pdata.steps = params[1]; 107 pdata.axis = params[2]; 108 pdata.relative_axis = false; 109 pdata.rollover = false; 110 pdata.gpio_a = params[3]; 111 pdata.gpio_b = params[4]; 112 113 if (params[5] == 1) { 114 pdata.inverted_a = 1; 115 pdata.inverted_b = 1; 116 } else { 117 pdata.inverted_a = 0; 118 pdata.inverted_b = 0; 119 } 120 121 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 122 if (err) 123 goto err_put; 124 125 err = platform_device_add(pdev); 126 if (err) 127 goto err_put; 128 129 devices[nr_devices++] = pdev; 130 return 0; 131 132err_put: 133 platform_device_put(pdev); 134err: 135 return err; 136} 137 138static int __init rotary_gpio_custom_probe(void) 139{ 140 int err; 141 142 printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); 143 144 err = rotary_gpio_custom_add_one(0, bus0); 145 if (err) 146 goto err; 147 148 err = rotary_gpio_custom_add_one(1, bus1); 149 if (err) 150 goto err; 151 152 err = rotary_gpio_custom_add_one(2, bus2); 153 if (err) 154 goto err; 155 156 err = rotary_gpio_custom_add_one(3, bus3); 157 if (err) 158 goto err; 159 160 if (!nr_devices) { 161 printk(KERN_ERR PFX "no bus parameter(s) specified\n"); 162 err = -ENODEV; 163 goto err; 164 } 165 166 return 0; 167 168err: 169 rotary_gpio_custom_cleanup(); 170 return err; 171} 172 173#ifdef MODULE 174static int __init rotary_gpio_custom_init(void) 175{ 176 return rotary_gpio_custom_probe(); 177} 178module_init(rotary_gpio_custom_init); 179 180static void __exit rotary_gpio_custom_exit(void) 181{ 182 rotary_gpio_custom_cleanup(); 183} 184module_exit(rotary_gpio_custom_exit); 185#else 186subsys_initcall(rotary_gpio_custom_probe); 187#endif /* MODULE*/ 188 189MODULE_LICENSE("GPL v2"); 190MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org >"); 191MODULE_AUTHOR("Claudio Mignanti <c.mignanti@gmail.com>"); 192MODULE_DESCRIPTION(DRV_DESC); 193MODULE_VERSION(DRV_VERSION); 194