sun4i-ts.c (6decea7c5438e2955f64e2513ec9a2fac7602a7d) | sun4i-ts.c (f09f98d3240b7ed2dd84ef6d84ff86df9d61e0f5) |
---|---|
1/* 2 * Allwinner sunxi resistive touchscreen controller driver 3 * 4 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> 5 * | 1/* 2 * Allwinner sunxi resistive touchscreen controller driver 3 * 4 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> 5 * |
6 * The hwmon parts are based on work by Corentin LABBE which is: 7 * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com> 8 * |
|
6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 11 unchanged lines hidden (view full) --- 25 * the last touch coordinate (as the dual-touch coordinates are worthless). 26 * 27 * These kinds of heuristics are just asking for trouble (and don't belong 28 * in the kernel). So this driver offers straight forward, reliable single 29 * touch functionality only. 30 */ 31 32#include <linux/err.h> | 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 11 unchanged lines hidden (view full) --- 28 * the last touch coordinate (as the dual-touch coordinates are worthless). 29 * 30 * These kinds of heuristics are just asking for trouble (and don't belong 31 * in the kernel). So this driver offers straight forward, reliable single 32 * touch functionality only. 33 */ 34 35#include <linux/err.h> |
36#include <linux/hwmon.h> |
|
33#include <linux/init.h> 34#include <linux/input.h> 35#include <linux/interrupt.h> 36#include <linux/io.h> 37#include <linux/module.h> 38#include <linux/of_platform.h> 39#include <linux/platform_device.h> 40#include <linux/slab.h> --- 60 unchanged lines hidden (view full) --- 101#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */ 102 103struct sun4i_ts_data { 104 struct device *dev; 105 struct input_dev *input; 106 void __iomem *base; 107 unsigned int irq; 108 bool ignore_fifo_data; | 37#include <linux/init.h> 38#include <linux/input.h> 39#include <linux/interrupt.h> 40#include <linux/io.h> 41#include <linux/module.h> 42#include <linux/of_platform.h> 43#include <linux/platform_device.h> 44#include <linux/slab.h> --- 60 unchanged lines hidden (view full) --- 105#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */ 106 107struct sun4i_ts_data { 108 struct device *dev; 109 struct input_dev *input; 110 void __iomem *base; 111 unsigned int irq; 112 bool ignore_fifo_data; |
113 int temp_data; |
|
109}; 110 | 114}; 115 |
111static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) | 116static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) |
112{ | 117{ |
113 struct sun4i_ts_data *ts = dev_id; 114 u32 reg_val, x, y; | 118 u32 x, y; |
115 | 119 |
116 reg_val = readl(ts->base + TP_INT_FIFOS); 117 | |
118 if (reg_val & FIFO_DATA_PENDING) { 119 x = readl(ts->base + TP_DATA); 120 y = readl(ts->base + TP_DATA); 121 /* The 1st location reported after an up event is unreliable */ 122 if (!ts->ignore_fifo_data) { 123 input_report_abs(ts->input, ABS_X, x); 124 input_report_abs(ts->input, ABS_Y, y); 125 /* --- 8 unchanged lines hidden (view full) --- 134 } 135 } 136 137 if (reg_val & TP_UP_PENDING) { 138 ts->ignore_fifo_data = true; 139 input_report_key(ts->input, BTN_TOUCH, 0); 140 input_sync(ts->input); 141 } | 120 if (reg_val & FIFO_DATA_PENDING) { 121 x = readl(ts->base + TP_DATA); 122 y = readl(ts->base + TP_DATA); 123 /* The 1st location reported after an up event is unreliable */ 124 if (!ts->ignore_fifo_data) { 125 input_report_abs(ts->input, ABS_X, x); 126 input_report_abs(ts->input, ABS_Y, y); 127 /* --- 8 unchanged lines hidden (view full) --- 136 } 137 } 138 139 if (reg_val & TP_UP_PENDING) { 140 ts->ignore_fifo_data = true; 141 input_report_key(ts->input, BTN_TOUCH, 0); 142 input_sync(ts->input); 143 } |
144} |
|
142 | 145 |
146static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) 147{ 148 struct sun4i_ts_data *ts = dev_id; 149 u32 reg_val; 150 151 reg_val = readl(ts->base + TP_INT_FIFOS); 152 153 if (reg_val & TEMP_DATA_PENDING) 154 ts->temp_data = readl(ts->base + TEMP_DATA); 155 156 if (ts->input) 157 sun4i_ts_irq_handle_input(ts, reg_val); 158 |
|
143 writel(reg_val, ts->base + TP_INT_FIFOS); 144 145 return IRQ_HANDLED; 146} 147 148static int sun4i_ts_open(struct input_dev *dev) 149{ 150 struct sun4i_ts_data *ts = input_get_drvdata(dev); 151 | 159 writel(reg_val, ts->base + TP_INT_FIFOS); 160 161 return IRQ_HANDLED; 162} 163 164static int sun4i_ts_open(struct input_dev *dev) 165{ 166 struct sun4i_ts_data *ts = input_get_drvdata(dev); 167 |
152 /* Flush, set trig level to 1, enable data and up irqs */ 153 writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1), 154 ts->base + TP_INT_FIFOC); | 168 /* Flush, set trig level to 1, enable temp, data and up irqs */ 169 writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | 170 TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
155 156 return 0; 157} 158 159static void sun4i_ts_close(struct input_dev *dev) 160{ 161 struct sun4i_ts_data *ts = input_get_drvdata(dev); 162 | 171 172 return 0; 173} 174 175static void sun4i_ts_close(struct input_dev *dev) 176{ 177 struct sun4i_ts_data *ts = input_get_drvdata(dev); 178 |
163 /* Deactivate all IRQs */ 164 writel(0, ts->base + TP_INT_FIFOC); | 179 /* Deactivate all input IRQs */ 180 writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
165} 166 | 181} 182 |
183static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, 184 char *buf) 185{ 186 struct sun4i_ts_data *ts = dev_get_drvdata(dev); 187 188 /* No temp_data until the first irq */ 189 if (ts->temp_data == -1) 190 return -EAGAIN; 191 192 return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); 193} 194 195static ssize_t show_temp_label(struct device *dev, 196 struct device_attribute *devattr, char *buf) 197{ 198 return sprintf(buf, "SoC temperature\n"); 199} 200 201static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); 202static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL); 203 204static struct attribute *sun4i_ts_attrs[] = { 205 &dev_attr_temp1_input.attr, 206 &dev_attr_temp1_label.attr, 207 NULL 208}; 209ATTRIBUTE_GROUPS(sun4i_ts); 210 |
|
167static int sun4i_ts_probe(struct platform_device *pdev) 168{ 169 struct sun4i_ts_data *ts; 170 struct device *dev = &pdev->dev; | 211static int sun4i_ts_probe(struct platform_device *pdev) 212{ 213 struct sun4i_ts_data *ts; 214 struct device *dev = &pdev->dev; |
215 struct device_node *np = dev->of_node; 216 struct device *hwmon; |
|
171 int error; | 217 int error; |
218 bool ts_attached; |
|
172 173 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); 174 if (!ts) 175 return -ENOMEM; 176 177 ts->dev = dev; 178 ts->ignore_fifo_data = true; | 219 220 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); 221 if (!ts) 222 return -ENOMEM; 223 224 ts->dev = dev; 225 ts->ignore_fifo_data = true; |
226 ts->temp_data = -1; |
|
179 | 227 |
180 ts->input = devm_input_allocate_device(dev); 181 if (!ts->input) 182 return -ENOMEM; | 228 ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); 229 if (ts_attached) { 230 ts->input = devm_input_allocate_device(dev); 231 if (!ts->input) 232 return -ENOMEM; |
183 | 233 |
184 ts->input->name = pdev->name; 185 ts->input->phys = "sun4i_ts/input0"; 186 ts->input->open = sun4i_ts_open; 187 ts->input->close = sun4i_ts_close; 188 ts->input->id.bustype = BUS_HOST; 189 ts->input->id.vendor = 0x0001; 190 ts->input->id.product = 0x0001; 191 ts->input->id.version = 0x0100; 192 ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 193 __set_bit(BTN_TOUCH, ts->input->keybit); 194 input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); 195 input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); 196 input_set_drvdata(ts->input, ts); | 234 ts->input->name = pdev->name; 235 ts->input->phys = "sun4i_ts/input0"; 236 ts->input->open = sun4i_ts_open; 237 ts->input->close = sun4i_ts_close; 238 ts->input->id.bustype = BUS_HOST; 239 ts->input->id.vendor = 0x0001; 240 ts->input->id.product = 0x0001; 241 ts->input->id.version = 0x0100; 242 ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 243 __set_bit(BTN_TOUCH, ts->input->keybit); 244 input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); 245 input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); 246 input_set_drvdata(ts->input, ts); 247 } |
197 198 ts->base = devm_ioremap_resource(dev, 199 platform_get_resource(pdev, IORESOURCE_MEM, 0)); 200 if (IS_ERR(ts->base)) 201 return PTR_ERR(ts->base); 202 203 ts->irq = platform_get_irq(pdev, 0); 204 error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts); --- 22 unchanged lines hidden (view full) --- 227 228 /* 229 * Set stylus up debounce to aprox 10 ms, enable debounce, and 230 * finally enable tp mode. 231 */ 232 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), 233 ts->base + TP_CTRL1); 234 | 248 249 ts->base = devm_ioremap_resource(dev, 250 platform_get_resource(pdev, IORESOURCE_MEM, 0)); 251 if (IS_ERR(ts->base)) 252 return PTR_ERR(ts->base); 253 254 ts->irq = platform_get_irq(pdev, 0); 255 error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts); --- 22 unchanged lines hidden (view full) --- 278 279 /* 280 * Set stylus up debounce to aprox 10 ms, enable debounce, and 281 * finally enable tp mode. 282 */ 283 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), 284 ts->base + TP_CTRL1); 285 |
235 error = input_register_device(ts->input); 236 if (error) 237 return error; | 286 hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", 287 ts, sun4i_ts_groups); 288 if (IS_ERR(hwmon)) 289 return PTR_ERR(hwmon); |
238 | 290 |
291 writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); 292 293 if (ts_attached) { 294 error = input_register_device(ts->input); 295 if (error) { 296 writel(0, ts->base + TP_INT_FIFOC); 297 return error; 298 } 299 } 300 |
|
239 platform_set_drvdata(pdev, ts); 240 return 0; 241} 242 | 301 platform_set_drvdata(pdev, ts); 302 return 0; 303} 304 |
305static int sun4i_ts_remove(struct platform_device *pdev) 306{ 307 struct sun4i_ts_data *ts = platform_get_drvdata(pdev); 308 309 /* Explicit unregister to avoid open/close changing the imask later */ 310 if (ts->input) 311 input_unregister_device(ts->input); 312 313 /* Deactivate all IRQs */ 314 writel(0, ts->base + TP_INT_FIFOC); 315 316 return 0; 317} 318 |
|
243static const struct of_device_id sun4i_ts_of_match[] = { 244 { .compatible = "allwinner,sun4i-a10-ts", }, 245 { /* sentinel */ } 246}; 247MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); 248 249static struct platform_driver sun4i_ts_driver = { 250 .driver = { 251 .owner = THIS_MODULE, 252 .name = "sun4i-ts", 253 .of_match_table = of_match_ptr(sun4i_ts_of_match), 254 }, 255 .probe = sun4i_ts_probe, | 319static const struct of_device_id sun4i_ts_of_match[] = { 320 { .compatible = "allwinner,sun4i-a10-ts", }, 321 { /* sentinel */ } 322}; 323MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); 324 325static struct platform_driver sun4i_ts_driver = { 326 .driver = { 327 .owner = THIS_MODULE, 328 .name = "sun4i-ts", 329 .of_match_table = of_match_ptr(sun4i_ts_of_match), 330 }, 331 .probe = sun4i_ts_probe, |
332 .remove = sun4i_ts_remove, |
|
256}; 257 258module_platform_driver(sun4i_ts_driver); 259 260MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver"); 261MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 262MODULE_LICENSE("GPL"); | 333}; 334 335module_platform_driver(sun4i_ts_driver); 336 337MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver"); 338MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 339MODULE_LICENSE("GPL"); |