Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: sun4i-ts - add support for temperature sensor

The sun4i resisitive touchscreen controller also comes with a built-in
temperature sensor. This commit adds support for it.

This commit also introduces a new "ts-attached" device-tree property,
when this is not set, the input part of the driver won't register. This way
the internal temperature sensor can be used to measure the SoC temperature
independent of there actually being a touchscreen attached to the controller.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Hans de Goede and committed by
Dmitry Torokhov
f09f98d3 6decea7c

+112 -29
+5
Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
··· 6 6 - reg: mmio address range of the chip 7 7 - interrupts: interrupt to which the chip is connected 8 8 9 + Optional properties: 10 + - allwinner,ts-attached: boolean indicating that an actual touchscreen is 11 + attached to the controller 12 + 9 13 Example: 10 14 11 15 rtp: rtp@01c25000 { 12 16 compatible = "allwinner,sun4i-a10-ts"; 13 17 reg = <0x01c25000 0x100>; 14 18 interrupts = <29>; 19 + allwinner,ts-attached; 15 20 };
+1
drivers/input/touchscreen/Kconfig
··· 900 900 config TOUCHSCREEN_SUN4I 901 901 tristate "Allwinner sun4i resistive touchscreen controller support" 902 902 depends on ARCH_SUNXI || COMPILE_TEST 903 + depends on HWMON 903 904 help 904 905 This selects support for the resistive touchscreen controller 905 906 found on Allwinner sunxi SoCs.
+106 -29
drivers/input/touchscreen/sun4i-ts.c
··· 3 3 * 4 4 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> 5 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 9 * This program is free software; you can redistribute it and/or modify 7 10 * it under the terms of the GNU General Public License as published by 8 11 * the Free Software Foundation; either version 2 of the License, or ··· 33 30 */ 34 31 35 32 #include <linux/err.h> 33 + #include <linux/hwmon.h> 36 34 #include <linux/init.h> 37 35 #include <linux/input.h> 38 36 #include <linux/interrupt.h> ··· 110 106 void __iomem *base; 111 107 unsigned int irq; 112 108 bool ignore_fifo_data; 109 + int temp_data; 113 110 }; 114 111 115 - static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) 112 + static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) 116 113 { 117 - struct sun4i_ts_data *ts = dev_id; 118 - u32 reg_val, x, y; 119 - 120 - reg_val = readl(ts->base + TP_INT_FIFOS); 114 + u32 x, y; 121 115 122 116 if (reg_val & FIFO_DATA_PENDING) { 123 117 x = readl(ts->base + TP_DATA); ··· 141 139 input_report_key(ts->input, BTN_TOUCH, 0); 142 140 input_sync(ts->input); 143 141 } 142 + } 143 + 144 + static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) 145 + { 146 + struct sun4i_ts_data *ts = dev_id; 147 + u32 reg_val; 148 + 149 + reg_val = readl(ts->base + TP_INT_FIFOS); 150 + 151 + if (reg_val & TEMP_DATA_PENDING) 152 + ts->temp_data = readl(ts->base + TEMP_DATA); 153 + 154 + if (ts->input) 155 + sun4i_ts_irq_handle_input(ts, reg_val); 144 156 145 157 writel(reg_val, ts->base + TP_INT_FIFOS); 146 158 ··· 165 149 { 166 150 struct sun4i_ts_data *ts = input_get_drvdata(dev); 167 151 168 - /* Flush, set trig level to 1, enable data and up irqs */ 169 - writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1), 170 - ts->base + TP_INT_FIFOC); 152 + /* Flush, set trig level to 1, enable temp, data and up irqs */ 153 + writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | 154 + TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC); 171 155 172 156 return 0; 173 157 } ··· 176 160 { 177 161 struct sun4i_ts_data *ts = input_get_drvdata(dev); 178 162 179 - /* Deactivate all IRQs */ 180 - writel(0, ts->base + TP_INT_FIFOC); 163 + /* Deactivate all input IRQs */ 164 + writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); 181 165 } 166 + 167 + static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, 168 + char *buf) 169 + { 170 + struct sun4i_ts_data *ts = dev_get_drvdata(dev); 171 + 172 + /* No temp_data until the first irq */ 173 + if (ts->temp_data == -1) 174 + return -EAGAIN; 175 + 176 + return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); 177 + } 178 + 179 + static ssize_t show_temp_label(struct device *dev, 180 + struct device_attribute *devattr, char *buf) 181 + { 182 + return sprintf(buf, "SoC temperature\n"); 183 + } 184 + 185 + static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); 186 + static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL); 187 + 188 + static struct attribute *sun4i_ts_attrs[] = { 189 + &dev_attr_temp1_input.attr, 190 + &dev_attr_temp1_label.attr, 191 + NULL 192 + }; 193 + ATTRIBUTE_GROUPS(sun4i_ts); 182 194 183 195 static int sun4i_ts_probe(struct platform_device *pdev) 184 196 { 185 197 struct sun4i_ts_data *ts; 186 198 struct device *dev = &pdev->dev; 199 + struct device_node *np = dev->of_node; 200 + struct device *hwmon; 187 201 int error; 202 + bool ts_attached; 188 203 189 204 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); 190 205 if (!ts) ··· 223 176 224 177 ts->dev = dev; 225 178 ts->ignore_fifo_data = true; 179 + ts->temp_data = -1; 226 180 227 - ts->input = devm_input_allocate_device(dev); 228 - if (!ts->input) 229 - return -ENOMEM; 181 + ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); 182 + if (ts_attached) { 183 + ts->input = devm_input_allocate_device(dev); 184 + if (!ts->input) 185 + return -ENOMEM; 230 186 231 - ts->input->name = pdev->name; 232 - ts->input->phys = "sun4i_ts/input0"; 233 - ts->input->open = sun4i_ts_open; 234 - ts->input->close = sun4i_ts_close; 235 - ts->input->id.bustype = BUS_HOST; 236 - ts->input->id.vendor = 0x0001; 237 - ts->input->id.product = 0x0001; 238 - ts->input->id.version = 0x0100; 239 - ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 240 - __set_bit(BTN_TOUCH, ts->input->keybit); 241 - input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); 242 - input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); 243 - input_set_drvdata(ts->input, ts); 187 + ts->input->name = pdev->name; 188 + ts->input->phys = "sun4i_ts/input0"; 189 + ts->input->open = sun4i_ts_open; 190 + ts->input->close = sun4i_ts_close; 191 + ts->input->id.bustype = BUS_HOST; 192 + ts->input->id.vendor = 0x0001; 193 + ts->input->id.product = 0x0001; 194 + ts->input->id.version = 0x0100; 195 + ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 196 + __set_bit(BTN_TOUCH, ts->input->keybit); 197 + input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); 198 + input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); 199 + input_set_drvdata(ts->input, ts); 200 + } 244 201 245 202 ts->base = devm_ioremap_resource(dev, 246 203 platform_get_resource(pdev, IORESOURCE_MEM, 0)); ··· 283 232 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), 284 233 ts->base + TP_CTRL1); 285 234 286 - error = input_register_device(ts->input); 287 - if (error) 288 - return error; 235 + hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", 236 + ts, sun4i_ts_groups); 237 + if (IS_ERR(hwmon)) 238 + return PTR_ERR(hwmon); 239 + 240 + writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); 241 + 242 + if (ts_attached) { 243 + error = input_register_device(ts->input); 244 + if (error) { 245 + writel(0, ts->base + TP_INT_FIFOC); 246 + return error; 247 + } 248 + } 289 249 290 250 platform_set_drvdata(pdev, ts); 251 + return 0; 252 + } 253 + 254 + static int sun4i_ts_remove(struct platform_device *pdev) 255 + { 256 + struct sun4i_ts_data *ts = platform_get_drvdata(pdev); 257 + 258 + /* Explicit unregister to avoid open/close changing the imask later */ 259 + if (ts->input) 260 + input_unregister_device(ts->input); 261 + 262 + /* Deactivate all IRQs */ 263 + writel(0, ts->base + TP_INT_FIFOC); 264 + 291 265 return 0; 292 266 } 293 267 ··· 329 253 .of_match_table = of_match_ptr(sun4i_ts_of_match), 330 254 }, 331 255 .probe = sun4i_ts_probe, 256 + .remove = sun4i_ts_remove, 332 257 }; 333 258 334 259 module_platform_driver(sun4i_ts_driver);