void __iomem *base; /* * 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
/* handle touchscreen's physical behaviour */ /* samples per coordinate */ unsignedint over_sample_cnt; /* time clocks between samples */ unsignedint over_sample_delay; /* time in clocks to wait after the plates where switched */ unsignedint settling_delay;
spinlock_t lock;
};
staticvoid mxs_lradc_setup_ts_channel(struct mxs_lradc_ts *ts, unsignedint ch)
{ /* * prepare for oversampling conversion * * from the datasheet: * "The ACCUMULATE bit in the appropriate channel register * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; * otherwise, the IRQs will not fire."
*/
writel(LRADC_CH_ACCUMULATE |
LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1),
ts->base + LRADC_CH(ch));
/* from the datasheet: * "Software must clear this register in preparation for a * multi-cycle accumulation.
*/
writel(LRADC_CH_VALUE_MASK,
ts->base + LRADC_CH(ch) + STMP_OFFSET_REG_CLR);
/* * prepare the delay/loop unit according to the oversampling count * * from the datasheet: * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1, * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise, * the LRADC will not trigger the delay group."
*/
writel(LRADC_DELAY_TRIGGER(1 << ch) | LRADC_DELAY_TRIGGER_DELAYS(0) |
LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
ts->base + LRADC_DELAY(3));
/* * after changing the touchscreen plates setting * the signals need some initial time to settle. Start the * SoC's delay unit and start the conversion later * and automatically.
*/
writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
ts->base + LRADC_DELAY(2));
}
/* * Pressure detection is special: * We want to do both required measurements for the pressure detection in * one turn. Use the hardware features to chain both conversions and let the * hardware report one interrupt if both conversions are done
*/ staticvoid mxs_lradc_setup_ts_pressure(struct mxs_lradc_ts *ts, unsignedint ch1, unsignedint ch2)
{
u32 reg;
/* * prepare for oversampling conversion * * from the datasheet: * "The ACCUMULATE bit in the appropriate channel register * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; * otherwise, the IRQs will not fire."
*/
reg = LRADC_CH_ACCUMULATE |
LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1);
writel(reg, ts->base + LRADC_CH(ch1));
writel(reg, ts->base + LRADC_CH(ch2));
/* from the datasheet: * "Software must clear this register in preparation for a * multi-cycle accumulation.
*/
writel(LRADC_CH_VALUE_MASK,
ts->base + LRADC_CH(ch1) + STMP_OFFSET_REG_CLR);
writel(LRADC_CH_VALUE_MASK,
ts->base + LRADC_CH(ch2) + STMP_OFFSET_REG_CLR);
/* prepare the delay/loop unit according to the oversampling count */
writel(LRADC_DELAY_TRIGGER(1 << ch1) | LRADC_DELAY_TRIGGER(1 << ch2) |
LRADC_DELAY_TRIGGER_DELAYS(0) |
LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
ts->base + LRADC_DELAY(3));
/* * after changing the touchscreen plates setting * the signals need some initial time to settle. Start the * SoC's delay unit and start the conversion later * and automatically.
*/
writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
ts->base + LRADC_DELAY(2));
}
/* * In order to detect a touch event the 'touch detect enable' bit * enables: * - a weak pullup to the X+ connector * - a strong ground at the Y- connector
*/
writel(info[lradc->soc].mask,
ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
writel(info[lradc->soc].bit,
ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
}
/* * YP(meas)--+-------------+ * | |--+ * | | | * YM(open)--+-------------+ | * +--------------+ * | | * XP(+) XM(-) * * (+) means here 1.85 V * (-) means here GND
*/ staticvoid mxs_lradc_prepare_x_pos(struct mxs_lradc_ts *ts)
{ struct mxs_lradc *lradc = ts->lradc;
staticvoid mxs_lradc_start_touch_event(struct mxs_lradc_ts *ts)
{
writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
writel(LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1),
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); /* * start with the Y-pos, because it uses nearly the same plate * settings like the touch detection
*/
mxs_lradc_prepare_y_pos(ts);
}
staticvoid mxs_lradc_complete_touch_event(struct mxs_lradc_ts *ts)
{
mxs_lradc_setup_touch_detection(ts);
ts->cur_plate = LRADC_SAMPLE_VALID; /* * start a dummy conversion to burn time to settle the signals * note: we are not interested in the conversion's value
*/
writel(0, ts->base + LRADC_CH(TOUCHSCREEN_VCHANNEL1));
writel(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2),
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
writel(LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10),
ts->base + LRADC_DELAY(2));
}
/* * in order to avoid false measurements, report only samples where * the surface is still touched after the position measurement
*/ staticvoid mxs_lradc_finish_touch_event(struct mxs_lradc_ts *ts, bool valid)
{ /* if it is still touched, report the sample */ if (valid && mxs_lradc_check_touch_event(ts)) {
ts->ts_valid = true;
mxs_lradc_report_ts_event(ts);
}
/* if it is even still touched, continue with the next measurement */ if (mxs_lradc_check_touch_event(ts)) {
mxs_lradc_prepare_y_pos(ts); return;
}
if (ts->ts_valid) { /* signal the release */
ts->ts_valid = false;
input_report_key(ts->ts_input, BTN_TOUCH, 0);
input_sync(ts->ts_input);
}
/* if it is released, wait for the next touch via IRQ */
ts->cur_plate = LRADC_TOUCH;
writel(0, ts->base + LRADC_DELAY(2));
writel(0, ts->base + LRADC_DELAY(3));
writel(LRADC_CTRL1_TOUCH_DETECT_IRQ |
LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1),
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
}
/* touchscreen's state machine */ staticvoid mxs_lradc_handle_touch(struct mxs_lradc_ts *ts)
{ switch (ts->cur_plate) { case LRADC_TOUCH: if (mxs_lradc_check_touch_event(ts))
mxs_lradc_start_touch_event(ts);
writel(LRADC_CTRL1_TOUCH_DETECT_IRQ,
ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); return;
case LRADC_SAMPLE_Y:
ts->ts_y_pos =
mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
mxs_lradc_prepare_x_pos(ts); return;
case LRADC_SAMPLE_X:
ts->ts_x_pos =
mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
mxs_lradc_prepare_pressure(ts); return;
case LRADC_SAMPLE_PRESSURE:
ts->ts_pressure =
mxs_lradc_read_ts_pressure(ts,
TOUCHSCREEN_VCHANNEL2,
TOUCHSCREEN_VCHANNEL1);
mxs_lradc_complete_touch_event(ts); return;
case LRADC_SAMPLE_VALID:
mxs_lradc_finish_touch_event(ts, 1); break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.