Linux Audio

Check our new training course

Loading...
v6.8
  1/*
  2 * Touchscreen driver for the TS-4800 board
  3 *
  4 * Copyright (c) 2015 - Savoir-faire Linux
  5 *
  6 * This file is licensed under the terms of the GNU General Public
  7 * License version 2. This program is licensed "as is" without any
  8 * warranty of any kind, whether express or implied.
  9 */
 10
 11#include <linux/bitops.h>
 12#include <linux/input.h>
 13#include <linux/io.h>
 14#include <linux/kernel.h>
 15#include <linux/mfd/syscon.h>
 16#include <linux/module.h>
 17#include <linux/of.h>
 18#include <linux/platform_device.h>
 19#include <linux/regmap.h>
 20
 21/* polling interval in ms */
 22#define POLL_INTERVAL		3
 23
 24#define DEBOUNCE_COUNT		1
 25
 26/* sensor values are 12-bit wide */
 27#define MAX_12BIT		((1 << 12) - 1)
 28
 29#define PENDOWN_MASK		0x1
 30
 31#define X_OFFSET		0x0
 32#define Y_OFFSET		0x2
 33
 34struct ts4800_ts {
 35	struct input_dev        *input;
 36	struct device           *dev;
 37	char                    phys[32];
 38
 39	void __iomem            *base;
 40	struct regmap           *regmap;
 41	unsigned int            reg;
 42	unsigned int            bit;
 43
 44	bool                    pendown;
 45	int                     debounce;
 46};
 47
 48static int ts4800_ts_open(struct input_dev *input_dev)
 49{
 50	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 51	int error;
 52
 53	ts->pendown = false;
 54	ts->debounce = DEBOUNCE_COUNT;
 55
 56	error = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
 57	if (error) {
 58		dev_warn(ts->dev, "Failed to enable touchscreen: %d\n", error);
 59		return error;
 60	}
 61
 62	return 0;
 63}
 64
 65static void ts4800_ts_close(struct input_dev *input_dev)
 66{
 67	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 68	int ret;
 69
 70	ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
 71	if (ret)
 72		dev_warn(ts->dev, "Failed to disable touchscreen\n");
 73
 74}
 75
 76static void ts4800_ts_poll(struct input_dev *input_dev)
 77{
 78	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 79	u16 last_x = readw(ts->base + X_OFFSET);
 80	u16 last_y = readw(ts->base + Y_OFFSET);
 81	bool pendown = last_x & PENDOWN_MASK;
 82
 83	if (pendown) {
 84		if (ts->debounce) {
 85			ts->debounce--;
 86			return;
 87		}
 88
 89		if (!ts->pendown) {
 90			input_report_key(input_dev, BTN_TOUCH, 1);
 91			ts->pendown = true;
 92		}
 93
 94		last_x = ((~last_x) >> 4) & MAX_12BIT;
 95		last_y = ((~last_y) >> 4) & MAX_12BIT;
 96
 97		input_report_abs(input_dev, ABS_X, last_x);
 98		input_report_abs(input_dev, ABS_Y, last_y);
 99		input_sync(input_dev);
100	} else if (ts->pendown) {
101		ts->pendown = false;
102		ts->debounce = DEBOUNCE_COUNT;
103		input_report_key(input_dev, BTN_TOUCH, 0);
104		input_sync(input_dev);
105	}
106}
107
108static int ts4800_parse_dt(struct platform_device *pdev,
109			   struct ts4800_ts *ts)
110{
111	struct device *dev = &pdev->dev;
112	struct device_node *np = dev->of_node;
113	struct device_node *syscon_np;
114	u32 reg, bit;
115	int error;
116
117	syscon_np = of_parse_phandle(np, "syscon", 0);
118	if (!syscon_np) {
119		dev_err(dev, "no syscon property\n");
120		return -ENODEV;
121	}
122
123	ts->regmap = syscon_node_to_regmap(syscon_np);
124	of_node_put(syscon_np);
125	if (IS_ERR(ts->regmap)) {
126		dev_err(dev, "cannot get parent's regmap\n");
127		return PTR_ERR(ts->regmap);
128	}
129
130	error = of_property_read_u32_index(np, "syscon", 1, &reg);
131	if (error < 0) {
132		dev_err(dev, "no offset in syscon\n");
133		return error;
134	}
135
136	ts->reg = reg;
137
138	error = of_property_read_u32_index(np, "syscon", 2, &bit);
139	if (error < 0) {
140		dev_err(dev, "no bit in syscon\n");
141		return error;
142	}
143
144	ts->bit = BIT(bit);
145
146	return 0;
147}
148
149static int ts4800_ts_probe(struct platform_device *pdev)
150{
151	struct input_dev *input_dev;
152	struct ts4800_ts *ts;
153	int error;
154
155	ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
156	if (!ts)
157		return -ENOMEM;
158
159	error = ts4800_parse_dt(pdev, ts);
160	if (error)
161		return error;
162
163	ts->base = devm_platform_ioremap_resource(pdev, 0);
164	if (IS_ERR(ts->base))
165		return PTR_ERR(ts->base);
166
167	input_dev = devm_input_allocate_device(&pdev->dev);
168	if (!input_dev)
169		return -ENOMEM;
170
171	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
172	ts->input = input_dev;
173	ts->dev = &pdev->dev;
174
175	input_set_drvdata(input_dev, ts);
176
177	input_dev->name = "TS-4800 Touchscreen";
178	input_dev->phys = ts->phys;
179
180	input_dev->open = ts4800_ts_open;
181	input_dev->close = ts4800_ts_close;
182
183	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
184	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
185	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
186
187	error = input_setup_polling(input_dev, ts4800_ts_poll);
188	if (error) {
189		dev_err(&pdev->dev, "Unable to set up polling: %d\n", error);
190		return error;
191	}
192
193	input_set_poll_interval(input_dev, POLL_INTERVAL);
194
195	error = input_register_device(input_dev);
196	if (error) {
197		dev_err(&pdev->dev,
198			"Unable to register input device: %d\n", error);
199		return error;
200	}
201
202	return 0;
203}
204
205static const struct of_device_id ts4800_ts_of_match[] = {
206	{ .compatible = "technologic,ts4800-ts", },
207	{ },
208};
209MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
210
211static struct platform_driver ts4800_ts_driver = {
212	.driver = {
213		.name = "ts4800-ts",
214		.of_match_table = ts4800_ts_of_match,
215	},
216	.probe = ts4800_ts_probe,
217};
218module_platform_driver(ts4800_ts_driver);
219
220MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
221MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
222MODULE_LICENSE("GPL v2");
223MODULE_ALIAS("platform:ts4800_ts");
v6.2
  1/*
  2 * Touchscreen driver for the TS-4800 board
  3 *
  4 * Copyright (c) 2015 - Savoir-faire Linux
  5 *
  6 * This file is licensed under the terms of the GNU General Public
  7 * License version 2. This program is licensed "as is" without any
  8 * warranty of any kind, whether express or implied.
  9 */
 10
 11#include <linux/bitops.h>
 12#include <linux/input.h>
 13#include <linux/io.h>
 14#include <linux/kernel.h>
 15#include <linux/mfd/syscon.h>
 16#include <linux/module.h>
 17#include <linux/of.h>
 18#include <linux/platform_device.h>
 19#include <linux/regmap.h>
 20
 21/* polling interval in ms */
 22#define POLL_INTERVAL		3
 23
 24#define DEBOUNCE_COUNT		1
 25
 26/* sensor values are 12-bit wide */
 27#define MAX_12BIT		((1 << 12) - 1)
 28
 29#define PENDOWN_MASK		0x1
 30
 31#define X_OFFSET		0x0
 32#define Y_OFFSET		0x2
 33
 34struct ts4800_ts {
 35	struct input_dev        *input;
 36	struct device           *dev;
 37	char                    phys[32];
 38
 39	void __iomem            *base;
 40	struct regmap           *regmap;
 41	unsigned int            reg;
 42	unsigned int            bit;
 43
 44	bool                    pendown;
 45	int                     debounce;
 46};
 47
 48static int ts4800_ts_open(struct input_dev *input_dev)
 49{
 50	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 51	int error;
 52
 53	ts->pendown = false;
 54	ts->debounce = DEBOUNCE_COUNT;
 55
 56	error = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
 57	if (error) {
 58		dev_warn(ts->dev, "Failed to enable touchscreen: %d\n", error);
 59		return error;
 60	}
 61
 62	return 0;
 63}
 64
 65static void ts4800_ts_close(struct input_dev *input_dev)
 66{
 67	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 68	int ret;
 69
 70	ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
 71	if (ret)
 72		dev_warn(ts->dev, "Failed to disable touchscreen\n");
 73
 74}
 75
 76static void ts4800_ts_poll(struct input_dev *input_dev)
 77{
 78	struct ts4800_ts *ts = input_get_drvdata(input_dev);
 79	u16 last_x = readw(ts->base + X_OFFSET);
 80	u16 last_y = readw(ts->base + Y_OFFSET);
 81	bool pendown = last_x & PENDOWN_MASK;
 82
 83	if (pendown) {
 84		if (ts->debounce) {
 85			ts->debounce--;
 86			return;
 87		}
 88
 89		if (!ts->pendown) {
 90			input_report_key(input_dev, BTN_TOUCH, 1);
 91			ts->pendown = true;
 92		}
 93
 94		last_x = ((~last_x) >> 4) & MAX_12BIT;
 95		last_y = ((~last_y) >> 4) & MAX_12BIT;
 96
 97		input_report_abs(input_dev, ABS_X, last_x);
 98		input_report_abs(input_dev, ABS_Y, last_y);
 99		input_sync(input_dev);
100	} else if (ts->pendown) {
101		ts->pendown = false;
102		ts->debounce = DEBOUNCE_COUNT;
103		input_report_key(input_dev, BTN_TOUCH, 0);
104		input_sync(input_dev);
105	}
106}
107
108static int ts4800_parse_dt(struct platform_device *pdev,
109			   struct ts4800_ts *ts)
110{
111	struct device *dev = &pdev->dev;
112	struct device_node *np = dev->of_node;
113	struct device_node *syscon_np;
114	u32 reg, bit;
115	int error;
116
117	syscon_np = of_parse_phandle(np, "syscon", 0);
118	if (!syscon_np) {
119		dev_err(dev, "no syscon property\n");
120		return -ENODEV;
121	}
122
123	ts->regmap = syscon_node_to_regmap(syscon_np);
124	of_node_put(syscon_np);
125	if (IS_ERR(ts->regmap)) {
126		dev_err(dev, "cannot get parent's regmap\n");
127		return PTR_ERR(ts->regmap);
128	}
129
130	error = of_property_read_u32_index(np, "syscon", 1, &reg);
131	if (error < 0) {
132		dev_err(dev, "no offset in syscon\n");
133		return error;
134	}
135
136	ts->reg = reg;
137
138	error = of_property_read_u32_index(np, "syscon", 2, &bit);
139	if (error < 0) {
140		dev_err(dev, "no bit in syscon\n");
141		return error;
142	}
143
144	ts->bit = BIT(bit);
145
146	return 0;
147}
148
149static int ts4800_ts_probe(struct platform_device *pdev)
150{
151	struct input_dev *input_dev;
152	struct ts4800_ts *ts;
153	int error;
154
155	ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
156	if (!ts)
157		return -ENOMEM;
158
159	error = ts4800_parse_dt(pdev, ts);
160	if (error)
161		return error;
162
163	ts->base = devm_platform_ioremap_resource(pdev, 0);
164	if (IS_ERR(ts->base))
165		return PTR_ERR(ts->base);
166
167	input_dev = devm_input_allocate_device(&pdev->dev);
168	if (!input_dev)
169		return -ENOMEM;
170
171	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
172	ts->input = input_dev;
173	ts->dev = &pdev->dev;
174
175	input_set_drvdata(input_dev, ts);
176
177	input_dev->name = "TS-4800 Touchscreen";
178	input_dev->phys = ts->phys;
179
180	input_dev->open = ts4800_ts_open;
181	input_dev->close = ts4800_ts_close;
182
183	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
184	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
185	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
186
187	error = input_setup_polling(input_dev, ts4800_ts_poll);
188	if (error) {
189		dev_err(&pdev->dev, "Unable to set up polling: %d\n", error);
190		return error;
191	}
192
193	input_set_poll_interval(input_dev, POLL_INTERVAL);
194
195	error = input_register_device(input_dev);
196	if (error) {
197		dev_err(&pdev->dev,
198			"Unable to register input device: %d\n", error);
199		return error;
200	}
201
202	return 0;
203}
204
205static const struct of_device_id ts4800_ts_of_match[] = {
206	{ .compatible = "technologic,ts4800-ts", },
207	{ },
208};
209MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
210
211static struct platform_driver ts4800_ts_driver = {
212	.driver = {
213		.name = "ts4800-ts",
214		.of_match_table = ts4800_ts_of_match,
215	},
216	.probe = ts4800_ts_probe,
217};
218module_platform_driver(ts4800_ts_driver);
219
220MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
221MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
222MODULE_LICENSE("GPL v2");
223MODULE_ALIAS("platform:ts4800_ts");