unsigned long is_divided;
/*
- * Touchscreen LRADC channels receives a private slot in the CTRL4
- * register, the slot #7. Therefore only 7 slots instead of 8 in the
- * CTRL4 register can be mapped to LRADC channels when using the
- * touchscreen.
- *
+ * When the touchscreen is enabled, we give it two private virtual
+ * channels: #6 and #7. This means that only 6 virtual channels (instead
+ * of 8) will be available for buffered capture.
+ */
+#define TOUCHSCREEN_VCHANNEL1 7
+#define TOUCHSCREEN_VCHANNEL2 6
+
+ /*
* Furthermore, certain LRADC channels are shared between touchscreen
* and/or touch-buttons and generic LRADC block. Therefore when using
* either of these, these channels are not available for the regular
#define LRADC_CTRL4 0x140
#define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4))
#define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4)
+#define LRADC_CTRL4_LRADCSELECT(n, x) \
+ (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
+ LRADC_CTRL4_LRADCSELECT_MASK(n))
#define LRADC_RESOLUTION 12
#define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1)
LRADC_STATUS_TOUCH_DETECT_RAW);
}
+static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
+ unsigned ch)
+{
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
+ LRADC_CTRL4);
+ mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
+}
+
static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
{
/*
LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
LRADC_DELAY(3));
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
- LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
- LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
- /* wake us again, when the complete conversion is done */
- mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1);
/*
* after changing the touchscreen plates setting
* the signals need some initial time to settle. Start the
LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
LRADC_DELAY(3));
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
- LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
- LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
- /* wake us again, when the conversions are done */
- mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1);
/*
* after changing the touchscreen plates setting
* the signals need some initial time to settle. Start the
#define TS_CH_XM 4
#define TS_CH_YM 5
-static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc)
-{
- u32 reg;
- int val;
-
- reg = readl(lradc->base + LRADC_CTRL1);
-
- /* only channels 3 to 5 are of interest here */
- if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) {
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) |
- LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1);
- val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP);
- } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) {
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) |
- LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1);
- val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM);
- } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) {
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) |
- LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1);
- val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM);
- } else {
- return -EIO;
- }
-
- mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
- mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-
- return val;
-}
-
/*
* YP(open)--+-------------+
* | |--+
mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
lradc->cur_plate = LRADC_SAMPLE_X;
- mxs_lradc_setup_ts_channel(lradc, TS_CH_YP);
+ mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+ mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
}
/*
mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
lradc->cur_plate = LRADC_SAMPLE_Y;
- mxs_lradc_setup_ts_channel(lradc, TS_CH_XM);
+ mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+ mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
}
/*
mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
- mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+ mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+ mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+ mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
+ TOUCHSCREEN_VCHANNEL1);
}
static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
}
+static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
+{
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ LRADC_CTRL1);
+ mxs_lradc_reg_set(lradc,
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
+ /*
+ * start with the Y-pos, because it uses nearly the same plate
+ * settings like the touch detection
+ */
+ mxs_lradc_prepare_y_pos(lradc);
+}
+
static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
{
input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
* start a dummy conversion to burn time to settle the signals
* note: we are not interested in the conversion's value
*/
- mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5));
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
- mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1);
- mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) |
+ mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+ mxs_lradc_reg_clear(lradc,
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
+ mxs_lradc_reg_wrt(lradc,
+ LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
LRADC_DELAY(2));
}
/* if it is released, wait for the next touch via IRQ */
lradc->cur_plate = LRADC_TOUCH;
- mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
+ mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
+ mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
}
/* touchscreen's state machine */
static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
{
- int val;
-
switch (lradc->cur_plate) {
case LRADC_TOUCH:
- /*
- * start with the Y-pos, because it uses nearly the same plate
- * settings like the touch detection
- */
- if (mxs_lradc_check_touch_event(lradc)) {
- mxs_lradc_reg_clear(lradc,
- LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
- LRADC_CTRL1);
- mxs_lradc_prepare_y_pos(lradc);
- }
+ if (mxs_lradc_check_touch_event(lradc))
+ mxs_lradc_start_touch_event(lradc);
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
LRADC_CTRL1);
return;
case LRADC_SAMPLE_Y:
- val = mxs_lradc_read_ts_channel(lradc);
- if (val < 0) {
- mxs_lradc_enable_touch_detection(lradc); /* re-start */
- return;
- }
- lradc->ts_y_pos = val;
+ lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc,
+ TOUCHSCREEN_VCHANNEL1);
mxs_lradc_prepare_x_pos(lradc);
return;
case LRADC_SAMPLE_X:
- val = mxs_lradc_read_ts_channel(lradc);
- if (val < 0) {
- mxs_lradc_enable_touch_detection(lradc); /* re-start */
- return;
- }
- lradc->ts_x_pos = val;
+ lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc,
+ TOUCHSCREEN_VCHANNEL1);
mxs_lradc_prepare_pressure(lradc);
return;
case LRADC_SAMPLE_PRESSURE:
- lradc->ts_pressure =
- mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+ lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc,
+ TOUCHSCREEN_VCHANNEL2,
+ TOUCHSCREEN_VCHANNEL1);
mxs_lradc_complete_touch_event(lradc);
return;
case LRADC_SAMPLE_VALID:
- val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */
mxs_lradc_finish_touch_event(lradc, 1);
break;
}
{
/* stop all interrupts from firing */
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
- LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) |
- LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5),
- LRADC_CTRL1);
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
/* Power-down touchscreen touch-detect circuitry. */
mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
struct iio_dev *iio = data;
struct mxs_lradc *lradc = iio_priv(iio);
unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+ uint32_t clr_irq = mxs_lradc_irq_mask(lradc);
const uint32_t ts_irq_mask =
LRADC_CTRL1_TOUCH_DETECT_IRQ |
- LRADC_CTRL1_LRADC_IRQ(2) |
- LRADC_CTRL1_LRADC_IRQ(3) |
- LRADC_CTRL1_LRADC_IRQ(4) |
- LRADC_CTRL1_LRADC_IRQ(5);
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
if (!(reg & mxs_lradc_irq_mask(lradc)))
return IRQ_NONE;
- if (lradc->use_touchscreen && (reg & ts_irq_mask))
+ if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
mxs_lradc_handle_touch(lradc);
+ /* Make sure we don't clear the next conversion's interrupt. */
+ clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+ }
+
if (iio_buffer_enabled(iio))
iio_trigger_poll(iio->trig);
else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
complete(&lradc->completion);
- mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
- LRADC_CTRL1);
+ mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
return IRQ_HANDLED;
}
if (lradc->use_touchbutton)
rsvd_chans++;
if (lradc->use_touchscreen)
- rsvd_chans++;
+ rsvd_chans += 2;
/* Test for attempts to map channels with special mode of operation. */
if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))