1 /* 2 * Amstrad E3 (Delta) keyboard port driver 3 * 4 * Copyright (c) 2006 Matt Callow 5 * Copyright (c) 2010 Janusz Krzysztofik 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * Thanks to Cliff Lawson for his help 12 * 13 * The Amstrad Delta keyboard (aka mailboard) uses normal PC-AT style serial 14 * transmission. The keyboard port is formed of two GPIO lines, for clock 15 * and data. Due to strict timing requirements of the interface, 16 * the serial data stream is read and processed by a FIQ handler. 17 * The resulting words are fetched by this driver from a circular buffer. 18 * 19 * Standard AT keyboard driver (atkbd) is used for handling the keyboard data. 20 * However, when used with the E3 mailboard that producecs non-standard 21 * scancodes, a custom key table must be prepared and loaded from userspace. 22 */ 23 #include <linux/gpio.h> 24 #include <linux/irq.h> 25 #include <linux/platform_device.h> 26 #include <linux/regulator/consumer.h> 27 #include <linux/serio.h> 28 #include <linux/slab.h> 29 #include <linux/module.h> 30 31 #include <mach/board-ams-delta.h> 32 33 #include <mach/ams-delta-fiq.h> 34 35 #define DRIVER_NAME "ams-delta-serio" 36 37 MODULE_AUTHOR("Matt Callow"); 38 MODULE_DESCRIPTION("AMS Delta (E3) keyboard port driver"); 39 MODULE_LICENSE("GPL"); 40 41 struct ams_delta_serio { 42 struct serio *serio; 43 struct regulator *vcc; 44 }; 45 46 static int check_data(struct serio *serio, int data) 47 { 48 int i, parity = 0; 49 50 /* check valid stop bit */ 51 if (!(data & 0x400)) { 52 dev_warn(&serio->dev, "invalid stop bit, data=0x%X\n", data); 53 return SERIO_FRAME; 54 } 55 /* calculate the parity */ 56 for (i = 1; i < 10; i++) { 57 if (data & (1 << i)) 58 parity++; 59 } 60 /* it should be odd */ 61 if (!(parity & 0x01)) { 62 dev_warn(&serio->dev, 63 "parity check failed, data=0x%X parity=0x%X\n", data, 64 parity); 65 return SERIO_PARITY; 66 } 67 return 0; 68 } 69 70 static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id) 71 { 72 struct ams_delta_serio *priv = dev_id; 73 int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF]; 74 int data, dfl; 75 u8 scancode; 76 77 fiq_buffer[FIQ_IRQ_PEND] = 0; 78 79 /* 80 * Read data from the circular buffer, check it 81 * and then pass it on the serio 82 */ 83 while (fiq_buffer[FIQ_KEYS_CNT] > 0) { 84 85 data = circ_buff[fiq_buffer[FIQ_HEAD_OFFSET]++]; 86 fiq_buffer[FIQ_KEYS_CNT]--; 87 if (fiq_buffer[FIQ_HEAD_OFFSET] == fiq_buffer[FIQ_BUF_LEN]) 88 fiq_buffer[FIQ_HEAD_OFFSET] = 0; 89 90 dfl = check_data(priv->serio, data); 91 scancode = (u8) (data >> 1) & 0xFF; 92 serio_interrupt(priv->serio, scancode, dfl); 93 } 94 return IRQ_HANDLED; 95 } 96 97 static int ams_delta_serio_open(struct serio *serio) 98 { 99 struct ams_delta_serio *priv = serio->port_data; 100 101 /* enable keyboard */ 102 return regulator_enable(priv->vcc); 103 } 104 105 static void ams_delta_serio_close(struct serio *serio) 106 { 107 struct ams_delta_serio *priv = serio->port_data; 108 109 /* disable keyboard */ 110 regulator_disable(priv->vcc); 111 } 112 113 static const struct gpio ams_delta_gpios[] __initconst_or_module = { 114 { 115 .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATA, 116 .flags = GPIOF_DIR_IN, 117 .label = "serio-data", 118 }, 119 { 120 .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK, 121 .flags = GPIOF_DIR_IN, 122 .label = "serio-clock", 123 }, 124 }; 125 126 static int ams_delta_serio_init(struct platform_device *pdev) 127 { 128 struct ams_delta_serio *priv; 129 struct serio *serio; 130 int err; 131 132 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 133 if (!priv) 134 return -ENOMEM; 135 136 err = gpio_request_array(ams_delta_gpios, 137 ARRAY_SIZE(ams_delta_gpios)); 138 if (err) { 139 dev_err(&pdev->dev, "Couldn't request gpio pins\n"); 140 goto serio; 141 } 142 143 priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); 144 if (IS_ERR(priv->vcc)) { 145 err = PTR_ERR(priv->vcc); 146 dev_err(&pdev->dev, "regulator request failed (%d)\n", err); 147 /* 148 * When running on a non-dt platform and requested regulator 149 * is not available, devm_regulator_get() never returns 150 * -EPROBE_DEFER as it is not able to justify if the regulator 151 * may still appear later. On the other hand, the board can 152 * still set full constriants flag at late_initcall in order 153 * to instruct devm_regulator_get() to returnn a dummy one 154 * if sufficient. Hence, if we get -ENODEV here, let's convert 155 * it to -EPROBE_DEFER and wait for the board to decide or 156 * let Deferred Probe infrastructure handle this error. 157 */ 158 if (err == -ENODEV) 159 err = -EPROBE_DEFER; 160 goto gpio; 161 } 162 163 err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 164 ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING, 165 DRIVER_NAME, priv); 166 if (err < 0) { 167 dev_err(&pdev->dev, "IRQ request failed (%d)\n", err); 168 goto gpio; 169 } 170 /* 171 * Since GPIO register handling for keyboard clock pin is performed 172 * at FIQ level, switch back from edge to simple interrupt handler 173 * to avoid bad interaction. 174 */ 175 irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 176 handle_simple_irq); 177 178 serio = kzalloc(sizeof(*serio), GFP_KERNEL); 179 if (!serio) { 180 err = -ENOMEM; 181 goto irq; 182 } 183 184 priv->serio = serio; 185 186 serio->id.type = SERIO_8042; 187 serio->open = ams_delta_serio_open; 188 serio->close = ams_delta_serio_close; 189 strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name)); 190 strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys)); 191 serio->dev.parent = &pdev->dev; 192 serio->port_data = priv; 193 194 serio_register_port(serio); 195 196 platform_set_drvdata(pdev, priv); 197 198 dev_info(&serio->dev, "%s\n", serio->name); 199 200 return 0; 201 202 irq: 203 free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), priv); 204 gpio: 205 gpio_free_array(ams_delta_gpios, 206 ARRAY_SIZE(ams_delta_gpios)); 207 serio: 208 return err; 209 } 210 211 static int ams_delta_serio_exit(struct platform_device *pdev) 212 { 213 struct ams_delta_serio *priv = platform_get_drvdata(pdev); 214 215 serio_unregister_port(priv->serio); 216 free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0); 217 gpio_free_array(ams_delta_gpios, 218 ARRAY_SIZE(ams_delta_gpios)); 219 220 return 0; 221 } 222 223 static struct platform_driver ams_delta_serio_driver = { 224 .probe = ams_delta_serio_init, 225 .remove = ams_delta_serio_exit, 226 .driver = { 227 .name = DRIVER_NAME 228 }, 229 }; 230 module_platform_driver(ams_delta_serio_driver); 231