Skip to content

Commit 84882b0

Browse files
alexandrebelloniNicolas Ferre
authored andcommitted
iio: adc: at91_adc: Add support for touchscreens without TSMR
Old ADCs, as present on the sam9rl and the sam9g45 don't have a TSMR register and the touchscreen support should be handled differently. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Acked-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
1 parent 2de0c01 commit 84882b0

File tree

3 files changed

+174
-47
lines changed

3 files changed

+174
-47
lines changed

arch/arm/mach-at91/include/mach/at91_adc.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#define AT91_ADC_START (1 << 1) /* Start Conversion */
2121

2222
#define AT91_ADC_MR 0x04 /* Mode Register */
23+
#define AT91_ADC_TSAMOD (3 << 0) /* ADC mode */
24+
#define AT91_ADC_TSAMOD_ADC_ONLY_MODE (0 << 0) /* ADC Mode */
25+
#define AT91_ADC_TSAMOD_TS_ONLY_MODE (1 << 0) /* Touch Screen Only Mode */
2326
#define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */
2427
#define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */
2528
#define AT91_ADC_TRGSEL_TC0 (0 << 1)
@@ -28,6 +31,7 @@
2831
#define AT91_ADC_TRGSEL_EXTERNAL (6 << 1)
2932
#define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */
3033
#define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */
34+
#define AT91_ADC_PENDET (1 << 6) /* Pen contact detection enable */
3135
#define AT91_ADC_PRESCAL_9260 (0x3f << 8) /* Prescalar Rate Selection */
3236
#define AT91_ADC_PRESCAL_9G45 (0xff << 8)
3337
#define AT91_ADC_PRESCAL_(x) ((x) << 8)
@@ -37,6 +41,12 @@
3741
#define AT91_ADC_STARTUP_(x) ((x) << 16)
3842
#define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */
3943
#define AT91_ADC_SHTIM_(x) ((x) << 24)
44+
#define AT91_ADC_PENDBC (0x0f << 28) /* Pen Debounce time */
45+
#define AT91_ADC_PENDBC_(x) ((x) << 28)
46+
47+
#define AT91_ADC_TSR 0x0C
48+
#define AT91_ADC_TSR_SHTIM (0xf << 24) /* Sample & Hold Time */
49+
#define AT91_ADC_TSR_SHTIM_(x) ((x) << 24)
4050

4151
#define AT91_ADC_CHER 0x10 /* Channel Enable Register */
4252
#define AT91_ADC_CHDR 0x14 /* Channel Disable Register */
@@ -60,6 +70,8 @@
6070
#define AT91_ADC_IER 0x24 /* Interrupt Enable Register */
6171
#define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */
6272
#define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */
73+
#define AT91RL_ADC_IER_PEN (1 << 20)
74+
#define AT91RL_ADC_IER_NOPEN (1 << 21)
6375
#define AT91_ADC_IER_PEN (1 << 29)
6476
#define AT91_ADC_IER_NOPEN (1 << 30)
6577
#define AT91_ADC_IER_XRDY (1 << 20)
@@ -102,6 +114,7 @@
102114
#define AT91_ADC_TRGR_TRGPER (0xffff << 16)
103115
#define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16)
104116
#define AT91_ADC_TRGR_TRGMOD (0x7 << 0)
117+
#define AT91_ADC_TRGR_NONE (0 << 0)
105118
#define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0)
106119

107120
#endif

drivers/iio/adc/at91_adc.c

Lines changed: 153 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
#define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
4747
#define TOUCH_PEN_DETECT_DEBOUNCE_US 200
4848

49+
#define MAX_RLPOS_BITS 10
50+
#define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */
51+
#define TOUCH_SHTIM 0xa
52+
4953
/**
5054
* struct at91_adc_reg_desc - Various informations relative to registers
5155
* @channel_base: Base offset for the channel data registers
@@ -83,12 +87,6 @@ struct at91_adc_caps {
8387
struct at91_adc_reg_desc registers;
8488
};
8589

86-
enum atmel_adc_ts_type {
87-
ATMEL_ADC_TOUCHSCREEN_NONE = 0,
88-
ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
89-
ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
90-
};
91-
9290
struct at91_adc_state {
9391
struct clk *adc_clk;
9492
u16 *buffer;
@@ -133,6 +131,11 @@ struct at91_adc_state {
133131

134132
u16 ts_sample_period_val;
135133
u32 ts_pressure_threshold;
134+
u16 ts_pendbc;
135+
136+
bool ts_bufferedmeasure;
137+
u32 ts_prev_absx;
138+
u32 ts_prev_absy;
136139
};
137140

138141
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -239,7 +242,72 @@ static int at91_ts_sample(struct at91_adc_state *st)
239242
return 0;
240243
}
241244

242-
static irqreturn_t at91_adc_interrupt(int irq, void *private)
245+
static irqreturn_t at91_adc_rl_interrupt(int irq, void *private)
246+
{
247+
struct iio_dev *idev = private;
248+
struct at91_adc_state *st = iio_priv(idev);
249+
u32 status = at91_adc_readl(st, st->registers->status_register);
250+
unsigned int reg;
251+
252+
status &= at91_adc_readl(st, AT91_ADC_IMR);
253+
if (status & st->registers->drdy_mask)
254+
handle_adc_eoc_trigger(irq, idev);
255+
256+
if (status & AT91RL_ADC_IER_PEN) {
257+
/* Disabling pen debounce is required to get a NOPEN irq */
258+
reg = at91_adc_readl(st, AT91_ADC_MR);
259+
reg &= ~AT91_ADC_PENDBC;
260+
at91_adc_writel(st, AT91_ADC_MR, reg);
261+
262+
at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN);
263+
at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_NOPEN
264+
| AT91_ADC_EOC(3));
265+
/* Set up period trigger for sampling */
266+
at91_adc_writel(st, st->registers->trigger_register,
267+
AT91_ADC_TRGR_MOD_PERIOD_TRIG |
268+
AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
269+
} else if (status & AT91RL_ADC_IER_NOPEN) {
270+
reg = at91_adc_readl(st, AT91_ADC_MR);
271+
reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC;
272+
at91_adc_writel(st, AT91_ADC_MR, reg);
273+
at91_adc_writel(st, st->registers->trigger_register,
274+
AT91_ADC_TRGR_NONE);
275+
276+
at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_NOPEN
277+
| AT91_ADC_EOC(3));
278+
at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN);
279+
st->ts_bufferedmeasure = false;
280+
input_report_key(st->ts_input, BTN_TOUCH, 0);
281+
input_sync(st->ts_input);
282+
} else if (status & AT91_ADC_EOC(3)) {
283+
/* Conversion finished */
284+
if (st->ts_bufferedmeasure) {
285+
/*
286+
* Last measurement is always discarded, since it can
287+
* be erroneous.
288+
* Always report previous measurement
289+
*/
290+
input_report_abs(st->ts_input, ABS_X, st->ts_prev_absx);
291+
input_report_abs(st->ts_input, ABS_Y, st->ts_prev_absy);
292+
input_report_key(st->ts_input, BTN_TOUCH, 1);
293+
input_sync(st->ts_input);
294+
} else
295+
st->ts_bufferedmeasure = true;
296+
297+
/* Now make new measurement */
298+
st->ts_prev_absx = at91_adc_readl(st, AT91_ADC_CHAN(st, 3))
299+
<< MAX_RLPOS_BITS;
300+
st->ts_prev_absx /= at91_adc_readl(st, AT91_ADC_CHAN(st, 2));
301+
302+
st->ts_prev_absy = at91_adc_readl(st, AT91_ADC_CHAN(st, 1))
303+
<< MAX_RLPOS_BITS;
304+
st->ts_prev_absy /= at91_adc_readl(st, AT91_ADC_CHAN(st, 0));
305+
}
306+
307+
return IRQ_HANDLED;
308+
}
309+
310+
static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private)
243311
{
244312
struct iio_dev *idev = private;
245313
struct at91_adc_state *st = iio_priv(idev);
@@ -672,6 +740,8 @@ static int at91_adc_probe_dt_ts(struct device_node *node,
672740
return -EINVAL;
673741
}
674742

743+
if (!st->caps->has_tsmr)
744+
return 0;
675745
prop = 0;
676746
of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
677747
st->ts_pressure_threshold = prop;
@@ -795,6 +865,7 @@ static int at91_adc_probe_pdata(struct at91_adc_state *st,
795865
st->trigger_number = pdata->trigger_number;
796866
st->trigger_list = pdata->trigger_list;
797867
st->registers = &st->caps->registers;
868+
st->touchscreen_type = pdata->touchscreen_type;
798869

799870
return 0;
800871
}
@@ -809,53 +880,72 @@ static int atmel_ts_open(struct input_dev *dev)
809880
{
810881
struct at91_adc_state *st = input_get_drvdata(dev);
811882

812-
at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
883+
if (st->caps->has_tsmr)
884+
at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
885+
else
886+
at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN);
813887
return 0;
814888
}
815889

816890
static void atmel_ts_close(struct input_dev *dev)
817891
{
818892
struct at91_adc_state *st = input_get_drvdata(dev);
819893

820-
at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
894+
if (st->caps->has_tsmr)
895+
at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
896+
else
897+
at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN);
821898
}
822899

823900
static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
824901
{
825-
u32 reg = 0, pendbc;
902+
u32 reg = 0;
826903
int i = 0;
827904

828-
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
829-
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
830-
else
831-
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
832-
833905
/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
834906
* pen detect noise.
835907
* The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
836908
*/
837-
pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
909+
st->ts_pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz /
910+
1000, 1);
838911

839-
while (pendbc >> ++i)
912+
while (st->ts_pendbc >> ++i)
840913
; /* Empty! Find the shift offset */
841-
if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
842-
pendbc = i;
914+
if (abs(st->ts_pendbc - (1 << i)) < abs(st->ts_pendbc - (1 << (i - 1))))
915+
st->ts_pendbc = i;
843916
else
844-
pendbc = i - 1;
917+
st->ts_pendbc = i - 1;
845918

846-
if (st->caps->has_tsmr) {
847-
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
848-
& AT91_ADC_TSMR_TSAV;
849-
reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
850-
reg |= AT91_ADC_TSMR_NOTSDMA;
851-
reg |= AT91_ADC_TSMR_PENDET_ENA;
852-
reg |= 0x03 << 8; /* TSFREQ, need bigger than TSAV */
853-
854-
at91_adc_writel(st, AT91_ADC_TSMR, reg);
855-
} else {
856-
/* TODO: for 9g45 which has no TSMR */
919+
if (!st->caps->has_tsmr) {
920+
reg = at91_adc_readl(st, AT91_ADC_MR);
921+
reg |= AT91_ADC_TSAMOD_TS_ONLY_MODE | AT91_ADC_PENDET;
922+
923+
reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC;
924+
at91_adc_writel(st, AT91_ADC_MR, reg);
925+
926+
reg = AT91_ADC_TSR_SHTIM_(TOUCH_SHTIM) & AT91_ADC_TSR_SHTIM;
927+
at91_adc_writel(st, AT91_ADC_TSR, reg);
928+
929+
st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US_RL *
930+
adc_clk_khz / 1000) - 1, 1);
931+
932+
return 0;
857933
}
858934

935+
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
936+
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
937+
else
938+
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
939+
940+
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
941+
& AT91_ADC_TSMR_TSAV;
942+
reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC;
943+
reg |= AT91_ADC_TSMR_NOTSDMA;
944+
reg |= AT91_ADC_TSMR_PENDET_ENA;
945+
reg |= 0x03 << 8; /* TSFREQ, needs to be bigger than TSAV */
946+
947+
at91_adc_writel(st, AT91_ADC_TSMR, reg);
948+
859949
/* Change adc internal resistor value for better pen detection,
860950
* default value is 100 kOhm.
861951
* 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
@@ -864,7 +954,7 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
864954
at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
865955
& AT91_ADC_ACR_PENDETSENS);
866956

867-
/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
957+
/* Sample Period Time = (TRGPER + 1) / ADCClock */
868958
st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
869959
adc_clk_khz / 1000) - 1, 1);
870960

@@ -893,17 +983,37 @@ static int at91_ts_register(struct at91_adc_state *st,
893983
__set_bit(EV_ABS, input->evbit);
894984
__set_bit(EV_KEY, input->evbit);
895985
__set_bit(BTN_TOUCH, input->keybit);
896-
input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
897-
input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
898-
input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
986+
if (st->caps->has_tsmr) {
987+
input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1,
988+
0, 0);
989+
input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1,
990+
0, 0);
991+
input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
992+
} else {
993+
if (st->touchscreen_type != ATMEL_ADC_TOUCHSCREEN_4WIRE) {
994+
dev_err(&pdev->dev,
995+
"This touchscreen controller only support 4 wires\n");
996+
ret = -EINVAL;
997+
goto err;
998+
}
999+
1000+
input_set_abs_params(input, ABS_X, 0, (1 << MAX_RLPOS_BITS) - 1,
1001+
0, 0);
1002+
input_set_abs_params(input, ABS_Y, 0, (1 << MAX_RLPOS_BITS) - 1,
1003+
0, 0);
1004+
}
8991005

9001006
st->ts_input = input;
9011007
input_set_drvdata(input, st);
9021008

9031009
ret = input_register_device(input);
9041010
if (ret)
905-
input_free_device(st->ts_input);
1011+
goto err;
1012+
1013+
return ret;
9061014

1015+
err:
1016+
input_free_device(st->ts_input);
9071017
return ret;
9081018
}
9091019

@@ -962,11 +1072,13 @@ static int at91_adc_probe(struct platform_device *pdev)
9621072
*/
9631073
at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
9641074
at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
965-
ret = request_irq(st->irq,
966-
at91_adc_interrupt,
967-
0,
968-
pdev->dev.driver->name,
969-
idev);
1075+
1076+
if (st->caps->has_tsmr)
1077+
ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0,
1078+
pdev->dev.driver->name, idev);
1079+
else
1080+
ret = request_irq(st->irq, at91_adc_rl_interrupt, 0,
1081+
pdev->dev.driver->name, idev);
9701082
if (ret) {
9711083
dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
9721084
return ret;
@@ -1070,12 +1182,6 @@ static int at91_adc_probe(struct platform_device *pdev)
10701182
goto error_disable_adc_clk;
10711183
}
10721184
} else {
1073-
if (!st->caps->has_tsmr) {
1074-
dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
1075-
ret = -ENODEV;
1076-
goto error_disable_adc_clk;
1077-
}
1078-
10791185
ret = at91_ts_register(st, pdev);
10801186
if (ret)
10811187
goto error_disable_adc_clk;

include/linux/platform_data/at91_adc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
#ifndef _AT91_ADC_H_
88
#define _AT91_ADC_H_
99

10+
enum atmel_adc_ts_type {
11+
ATMEL_ADC_TOUCHSCREEN_NONE = 0,
12+
ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
13+
ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
14+
};
15+
1016
/**
1117
* struct at91_adc_trigger - description of triggers
1218
* @name: name of the trigger advertised to the user
@@ -28,6 +34,7 @@ struct at91_adc_trigger {
2834
* @trigger_number: Number of triggers available in the ADC
2935
* @use_external_triggers: does the board has external triggers availables
3036
* @vref: Reference voltage for the ADC in millivolts
37+
* @touchscreen_type: If a touchscreen is connected, its type (4 or 5 wires)
3138
*/
3239
struct at91_adc_data {
3340
unsigned long channels_used;
@@ -36,6 +43,7 @@ struct at91_adc_data {
3643
u8 trigger_number;
3744
bool use_external_triggers;
3845
u16 vref;
46+
enum atmel_adc_ts_type touchscreen_type;
3947
};
4048

4149
extern void __init at91_add_device_adc(struct at91_adc_data *data);

0 commit comments

Comments
 (0)