sunxi: initial 3.14 patchset
[openwrt/openwrt.git] / target / linux / sunxi / patches-3.14 / 171-input-add-temp-sensor-support.patch
1 From d8b5553dbf60e519d565dbd83327b08865e960e2 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Fri, 27 Dec 2013 15:25:28 +0100
4 Subject: [PATCH] input: sun4i-ts: Add support for temperature sensor
5
6 The sun4i resisitive touchscreen controller also comes with a built-in
7 temperature sensor. This commit adds support for it.
8
9 This commit also introduces a new "ts-attached" device-tree property,
10 when this is not set, the input part of the driver won't register. This way
11 the internal temperature sensor can be used to measure the SoC temperature
12 independent of there actually being a touchscreen attached to the controller.
13
14 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
15 ---
16 .../bindings/input/touchscreen/sun4i.txt | 5 +
17 drivers/input/touchscreen/sun4i-ts.c | 140 ++++++++++++++++-----
18 2 files changed, 114 insertions(+), 31 deletions(-)
19
20 diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
21 index e45927e..6bac67b 100644
22 --- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
23 +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
24 @@ -6,10 +6,15 @@ Required properties:
25 - reg: mmio address range of the chip
26 - interrupts: interrupt to which the chip is connected
27
28 +Optional properties:
29 + - allwinner,ts-attached: boolean indicating that an actual touchscreen is
30 + attached to the controller
31 +
32 Example:
33
34 rtp: rtp@01c25000 {
35 compatible = "allwinner,sun4i-ts";
36 reg = <0x01c25000 0x100>;
37 interrupts = <29>;
38 + allwinner,ts-attached;
39 };
40 diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
41 index 5945219..16cbb01 100644
42 --- a/drivers/input/touchscreen/sun4i-ts.c
43 +++ b/drivers/input/touchscreen/sun4i-ts.c
44 @@ -3,6 +3,9 @@
45 *
46 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
47 *
48 + * The hwmon parts are based on work by Corentin LABBE which is:
49 + * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
50 + *
51 * This program is free software; you can redistribute it and/or modify
52 * it under the terms of the GNU General Public License as published by
53 * the Free Software Foundation; either version 2 of the License, or
54 @@ -30,6 +33,7 @@
55 */
56
57 #include <linux/err.h>
58 +#include <linux/hwmon.h>
59 #include <linux/init.h>
60 #include <linux/input.h>
61 #include <linux/interrupt.h>
62 @@ -106,14 +110,12 @@ struct sun4i_ts_data {
63 void __iomem *base;
64 unsigned int irq;
65 bool ignore_fifo_data;
66 + int temp_data;
67 };
68
69 -static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
70 +static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
71 {
72 - struct sun4i_ts_data *ts = dev_id;
73 - u32 reg_val, x, y;
74 -
75 - reg_val = readl(ts->base + TP_INT_FIFOS);
76 + u32 x, y;
77
78 if (reg_val & FIFO_DATA_PENDING) {
79 x = readl(ts->base + TP_DATA);
80 @@ -139,6 +141,20 @@ static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
81 input_report_key(ts->input, BTN_TOUCH, 0);
82 input_sync(ts->input);
83 }
84 +}
85 +
86 +static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
87 +{
88 + struct sun4i_ts_data *ts = dev_id;
89 + u32 reg_val;
90 +
91 + reg_val = readl(ts->base + TP_INT_FIFOS);
92 +
93 + if (reg_val & TEMP_DATA_PENDING)
94 + ts->temp_data = readl(ts->base + TEMP_DATA);
95 +
96 + if (ts->input)
97 + sun4i_ts_irq_handle_input(ts, reg_val);
98
99 writel(reg_val, ts->base + TP_INT_FIFOS);
100
101 @@ -149,9 +165,9 @@ static int sun4i_ts_open(struct input_dev *dev)
102 {
103 struct sun4i_ts_data *ts = input_get_drvdata(dev);
104
105 - /* Flush, set trig level to 1, enable data and up irqs */
106 - writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1),
107 - ts->base + TP_INT_FIFOC);
108 + /* Flush, set trig level to 1, enable temp, data and up irqs */
109 + writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
110 + TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
111
112 return 0;
113 }
114 @@ -160,15 +176,48 @@ static void sun4i_ts_close(struct input_dev *dev)
115 {
116 struct sun4i_ts_data *ts = input_get_drvdata(dev);
117
118 - /* Deactivate all IRQs */
119 - writel(0, ts->base + TP_INT_FIFOC);
120 + /* Deactivate all input IRQs */
121 + writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
122 +}
123 +
124 +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
125 + char *buf)
126 +{
127 + struct sun4i_ts_data *ts = dev_get_drvdata(dev);
128 +
129 + /* No temp_data until the first irq */
130 + if (ts->temp_data == -1)
131 + return -EAGAIN;
132 +
133 + return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
134 +}
135 +
136 +static ssize_t show_temp_label(struct device *dev,
137 + struct device_attribute *devattr, char *buf)
138 +{
139 + return sprintf(buf, "SoC temperature\n");
140 }
141
142 +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
143 +static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
144 +
145 +static struct attribute *sun4i_ts_attrs[] = {
146 + &dev_attr_temp1_input.attr,
147 + &dev_attr_temp1_label.attr,
148 + NULL
149 +};
150 +ATTRIBUTE_GROUPS(sun4i_ts);
151 +
152 static int sun4i_ts_probe(struct platform_device *pdev)
153 {
154 struct sun4i_ts_data *ts;
155 struct device *dev = &pdev->dev;
156 + struct device_node *np = dev->of_node;
157 + struct device *hwmon;
158 int ret;
159 + bool ts_attached;
160 +
161 + ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
162
163 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
164 if (!ts)
165 @@ -176,24 +225,27 @@ static int sun4i_ts_probe(struct platform_device *pdev)
166
167 ts->dev = dev;
168 ts->ignore_fifo_data = true;
169 -
170 - ts->input = devm_input_allocate_device(dev);
171 - if (!ts->input)
172 - return -ENOMEM;
173 -
174 - ts->input->name = pdev->name;
175 - ts->input->phys = "sun4i_ts/input0";
176 - ts->input->open = sun4i_ts_open;
177 - ts->input->close = sun4i_ts_close;
178 - ts->input->id.bustype = BUS_HOST;
179 - ts->input->id.vendor = 0x0001;
180 - ts->input->id.product = 0x0001;
181 - ts->input->id.version = 0x0100;
182 - ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
183 - set_bit(BTN_TOUCH, ts->input->keybit);
184 - input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
185 - input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
186 - input_set_drvdata(ts->input, ts);
187 + ts->temp_data = -1;
188 +
189 + if (ts_attached) {
190 + ts->input = devm_input_allocate_device(dev);
191 + if (!ts->input)
192 + return -ENOMEM;
193 +
194 + ts->input->name = pdev->name;
195 + ts->input->phys = "sun4i_ts/input0";
196 + ts->input->open = sun4i_ts_open;
197 + ts->input->close = sun4i_ts_close;
198 + ts->input->id.bustype = BUS_HOST;
199 + ts->input->id.vendor = 0x0001;
200 + ts->input->id.product = 0x0001;
201 + ts->input->id.version = 0x0100;
202 + ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
203 + set_bit(BTN_TOUCH, ts->input->keybit);
204 + input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
205 + input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
206 + input_set_drvdata(ts->input, ts);
207 + }
208
209 ts->base = devm_ioremap_resource(dev,
210 platform_get_resource(pdev, IORESOURCE_MEM, 0));
211 @@ -232,14 +284,39 @@ static int sun4i_ts_probe(struct platform_device *pdev)
212 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
213 ts->base + TP_CTRL1);
214
215 - ret = input_register_device(ts->input);
216 - if (ret)
217 - return ret;
218 + hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
219 + ts, sun4i_ts_groups);
220 + if (IS_ERR(hwmon))
221 + return PTR_ERR(hwmon);
222 +
223 + writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
224 +
225 + if (ts_attached) {
226 + ret = input_register_device(ts->input);
227 + if (ret) {
228 + writel(0, ts->base + TP_INT_FIFOC);
229 + return ret;
230 + }
231 + }
232
233 platform_set_drvdata(pdev, ts);
234 return 0;
235 }
236
237 +static int sun4i_ts_remove(struct platform_device *pdev)
238 +{
239 + struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
240 +
241 + /* Explicit unregister to avoid open/close changing the imask later */
242 + if (ts->input)
243 + input_unregister_device(ts->input);
244 +
245 + /* Deactivate all IRQs */
246 + writel(0, ts->base + TP_INT_FIFOC);
247 +
248 + return 0;
249 +}
250 +
251 static const struct of_device_id sun4i_ts_of_match[] = {
252 { .compatible = "allwinner,sun4i-ts", },
253 { /* sentinel */ }
254 @@ -253,6 +330,7 @@ static struct platform_driver sun4i_ts_driver = {
255 .of_match_table = of_match_ptr(sun4i_ts_of_match),
256 },
257 .probe = sun4i_ts_probe,
258 + .remove = sun4i_ts_remove,
259 };
260
261 module_platform_driver(sun4i_ts_driver);
262 --
263 2.0.3
264