aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/sun4i-ts.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 09:32:08 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 09:32:08 -0800
commit718749d56214aa97015fe01b76b6d6dd0c171796 (patch)
tree2f7355a3527c5579dc76721203d8a0011a40b19b /drivers/input/touchscreen/sun4i-ts.c
parente0c8453769fcaec654cd5870e84c63175658c842 (diff)
parent4ba24fef3eb3b142197135223b90ced2f319cd53 (diff)
downloadlinux-718749d56214aa97015fe01b76b6d6dd0c171796.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "The first round of updates for the input subsystem. A few new drivers (power button handler for AXP20x PMIC, tps65218 power button driver, sun4i keys driver, regulator haptic driver, NI Ettus Research USRP E3x0 button, Alwinner A10/A20 PS/2 controller). Updates to Synaptics and ALPS touchpad drivers (with more to come later), brand new Focaltech PS/2 support, update to Cypress driver to handle Gen5 (in addition to Gen3) devices, and number of other fixups to various drivers as well as input core" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (54 commits) Input: elan_i2c - fix wrong %p extension Input: evdev - do not queue SYN_DROPPED if queue is empty Input: gscps2 - fix MODULE_DEVICE_TABLE invocation Input: synaptics - use dmax in input_mt_assign_slots Input: pxa27x_keypad - remove unnecessary ARM includes Input: ti_am335x_tsc - replace delta filtering with median filtering ARM: dts: AM335x: Make charge delay a DT parameter for TSC Input: ti_am335x_tsc - read charge delay from DT Input: ti_am335x_tsc - remove udelay in interrupt handler Input: ti_am335x_tsc - interchange touchscreen and ADC steps Input: MT - add support for balanced slot assignment Input: drv2667 - remove wrong and unneeded drv2667-haptics modalias Input: drv260x - remove wrong and unneeded drv260x-haptics modalias Input: cap11xx - remove wrong and unneeded cap11xx modalias Input: sun4i-ts - add support for touchpanel controller on A31 Input: serio - add support for Alwinner A10/A20 PS/2 controller Input: gtco - use sign_extend32() for sign extension Input: elan_i2c - verify firmware signature applying it Input: elantech - remove stale comment from Kconfig Input: cyapa - off by one in cyapa_update_fw_store() ...
Diffstat (limited to 'drivers/input/touchscreen/sun4i-ts.c')
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 28a06749ae42..b93a28b955fd 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -34,6 +34,7 @@
#include <linux/err.h>
#include <linux/hwmon.h>
+#include <linux/thermal.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -71,6 +72,9 @@
#define TP_ADC_SELECT(x) ((x) << 3)
#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
+/* on sun6i, bits 3~6 are left shifted by 1 to 4~7 */
+#define SUN6I_TP_MODE_EN(x) ((x) << 5)
+
/* TP_CTRL2 bits */
#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
@@ -107,10 +111,13 @@
struct sun4i_ts_data {
struct device *dev;
struct input_dev *input;
+ struct thermal_zone_device *tz;
void __iomem *base;
unsigned int irq;
bool ignore_fifo_data;
int temp_data;
+ int temp_offset;
+ int temp_step;
};
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
@@ -180,16 +187,38 @@ static void sun4i_ts_close(struct input_dev *dev)
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
}
+static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
+{
+ /* No temp_data until the first irq */
+ if (ts->temp_data == -1)
+ return -EAGAIN;
+
+ *temp = (ts->temp_data - ts->temp_offset) * ts->temp_step;
+
+ return 0;
+}
+
+static int sun4i_get_tz_temp(void *data, long *temp)
+{
+ return sun4i_get_temp(data, temp);
+}
+
+static struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
+ .get_temp = sun4i_get_tz_temp,
+};
+
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
+ long temp;
+ int error;
- /* No temp_data until the first irq */
- if (ts->temp_data == -1)
- return -EAGAIN;
+ error = sun4i_get_temp(ts, &temp);
+ if (error)
+ return error;
- return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
+ return sprintf(buf, "%ld\n", temp);
}
static ssize_t show_temp_label(struct device *dev,
@@ -215,6 +244,7 @@ static int sun4i_ts_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct device *hwmon;
int error;
+ u32 reg;
bool ts_attached;
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
@@ -224,6 +254,25 @@ static int sun4i_ts_probe(struct platform_device *pdev)
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1;
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) {
+ /* Allwinner SDK has temperature = -271 + (value / 6) (C) */
+ ts->temp_offset = 1626;
+ ts->temp_step = 167;
+ } else {
+ /*
+ * The user manuals do not contain the formula for calculating
+ * the temperature. The formula used here is from the AXP209,
+ * which is designed by X-Powers, an affiliate of Allwinner:
+ *
+ * temperature = -144.7 + (value * 0.1)
+ *
+ * Allwinner does not have any documentation whatsoever for
+ * this hardware. Moreover, it is claimed that the sensor
+ * is inaccurate and cannot work properly.
+ */
+ ts->temp_offset = 1447;
+ ts->temp_step = 100;
+ }
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
if (ts_attached) {
@@ -280,20 +329,34 @@ static int sun4i_ts_probe(struct platform_device *pdev)
* Set stylus up debounce to aprox 10 ms, enable debounce, and
* finally enable tp mode.
*/
- writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
- ts->base + TP_CTRL1);
+ reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1);
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts"))
+ reg |= TP_MODE_EN(1);
+ else
+ reg |= SUN6I_TP_MODE_EN(1);
+ writel(reg, ts->base + TP_CTRL1);
+ /*
+ * The thermal core does not register hwmon devices for DT-based
+ * thermal zone sensors, such as this one.
+ */
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
ts, sun4i_ts_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
+ ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts,
+ &sun4i_ts_tz_ops);
+ if (IS_ERR(ts->tz))
+ ts->tz = NULL;
+
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
if (ts_attached) {
error = input_register_device(ts->input);
if (error) {
writel(0, ts->base + TP_INT_FIFOC);
+ thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
return error;
}
}
@@ -310,6 +373,8 @@ static int sun4i_ts_remove(struct platform_device *pdev)
if (ts->input)
input_unregister_device(ts->input);
+ thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
+
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
@@ -318,6 +383,7 @@ static int sun4i_ts_remove(struct platform_device *pdev)
static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", },
+ { .compatible = "allwinner,sun6i-a31-ts", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);