/* * The PENIRQ of TSC2046 controller is implemented as level shifter attached to * the X+ line. If voltage of the X+ line reaches a specific level the IRQ will * be activated or deactivated. * To make this kind of IRQ reusable as trigger following additions were * implemented: * - rate limiting: * For typical touchscreen use case, we need to trigger about each 10ms. * - hrtimer: * Continue triggering at least once after the IRQ was deactivated. Then * deactivate this trigger to stop sampling in order to reduce power * consumption.
*/
#define TI_TSC2046_NAME "tsc2046"
/* This driver doesn't aim at the peak continuous sample rate */ #define TI_TSC2046_MAX_SAMPLE_RATE 125000 #define TI_TSC2046_SAMPLE_BITS \
BITS_PER_TYPE(struct tsc2046_adc_atom) #define TI_TSC2046_MAX_CLK_FREQ \
(TI_TSC2046_MAX_SAMPLE_RATE * TI_TSC2046_SAMPLE_BITS)
/* * The mode bit sets the resolution of the ADC. With this bit low, the next * conversion has 12-bit resolution, whereas with this bit high, the next * conversion has 8-bit resolution. This driver is optimized for 12-bit mode. * So, for this driver, this bit should stay zero.
*/ #define TI_TSC2046_8BIT_MODE BIT(3)
/* * SER/DFR - The SER/DFR bit controls the reference mode, either single-ended * (high) or differential (low).
*/ #define TI_TSC2046_SER BIT(2)
/* * If VREF_ON and ADC_ON are both zero, then the chip operates in * auto-wake/suspend mode. In most case this bits should stay zero.
*/ #define TI_TSC2046_PD1_VREF_ON BIT(1) #define TI_TSC2046_PD0_ADC_ON BIT(0)
/* * All supported devices can do 8 or 12bit resolution. This driver * supports only 12bit mode, here we have a 16bit data transfer, where * the MSB and the 3 LSB are 0.
*/ #define TI_TSC2046_DATA_12BIT GENMASK(14, 3)
/* Represents a HW sample */ struct tsc2046_adc_atom { /* * Command transmitted to the controller. This field is empty on the RX * buffer.
*/
u8 cmd; /* * Data received from the controller. This field is empty for the TX * buffer
*/
__be16 data;
} __packed;
/* Layout of atomic buffers within big buffer */ struct tsc2046_adc_group_layout { /* Group offset within the SPI RX buffer */ unsignedint offset; /* * Amount of tsc2046_adc_atom structs within the same command gathered * within same group.
*/ unsignedint count; /* * Settling samples (tsc2046_adc_atom structs) which should be skipped * before good samples will start.
*/ unsignedint skip;
};
struct { /* Scan data for each channel */
u16 data[TI_TSC2046_MAX_CHAN]; /* Timestamp */
aligned_s64 ts;
} scan_buf;
/* * Lock to protect the layout and the SPI transfer buffer. * tsc2046_adc_group_layout can be changed within update_scan_mode(), * in this case the l[] and tx/rx buffer will be out of sync to each * other.
*/ struct mutex slock; struct tsc2046_adc_group_layout l[TI_TSC2046_MAX_CHAN]; struct tsc2046_adc_atom *rx; struct tsc2046_adc_atom *tx;
/* * Convert time to a number of samples which can be transferred within this * time.
*/ staticunsignedint tsc2046_adc_time_to_count(struct tsc2046_adc_priv *priv, unsignedlong time)
{ unsignedint bit_count, sample_count;
/* * if PD bits are 0, controller will automatically disable ADC, VREF and * enable IRQ.
*/ if (keep_power)
pd = TI_TSC2046_PD0_ADC_ON; else
pd = 0;
switch (ch_idx) { case TI_TSC2046_ADDR_TEMP1: case TI_TSC2046_ADDR_AUX: case TI_TSC2046_ADDR_VBAT: case TI_TSC2046_ADDR_TEMP0:
pd |= TI_TSC2046_SER; if (priv->internal_vref)
pd |= TI_TSC2046_PD1_VREF_ON;
}
/* * Do not enable automatic power down on working samples. Otherwise the * plates will never be completely charged.
*/
cmd = tsc2046_adc_get_cmd(priv, ch_idx, true);
for (i = 0; i < max_count - 1; i++)
tx_buf[i].cmd = cmd;
/* automatically power down on last sample */
tx_buf[i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
/* * We aren't using spi_write_then_read() because we need to be able * to get hold of the effective_speed_hz from the xfer
*/
ret = spi_sync(priv->spi, &msg); if (ret) {
dev_err_ratelimited(&priv->spi->dev, "SPI transfer failed %pe\n",
ERR_PTR(ret)); return ret;
}
if (effective_speed_hz)
*effective_speed_hz = xfer.effective_speed_hz;
for (i = 0; i < max_count - count_skip; i++) {
val = tsc2046_adc_get_value(&rx_buf[count_skip + i]);
val_normalized += val;
}
/* * Do not enable automatic power down on working samples. Otherwise the * plates will never be completely charged.
*/
cmd = tsc2046_adc_get_cmd(priv, ch_idx, true);
for (i = 0; i < l->count - 1; i++)
priv->tx[l->offset + i].cmd = cmd;
/* automatically power down on last sample */
priv->tx[l->offset + i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
}
static u16 tsc2046_adc_get_val(struct tsc2046_adc_priv *priv, int group)
{ struct tsc2046_adc_group_layout *l; unsignedint val, val_normalized = 0; int valid_count, i;
l = &priv->l[group];
valid_count = l->count - l->skip;
for (i = 0; i < valid_count; i++) {
val = tsc2046_adc_get_value(&priv->rx[l->offset + l->skip + i]);
val_normalized += val;
}
staticint tsc2046_adc_scan(struct iio_dev *indio_dev)
{ struct tsc2046_adc_priv *priv = iio_priv(indio_dev); struct device *dev = &priv->spi->dev; int group; int ret;
ret = spi_sync(priv->spi, &priv->msg); if (ret < 0) {
dev_err_ratelimited(dev, "SPI transfer failed: %pe\n", ERR_PTR(ret)); return ret;
}
for (group = 0; group < priv->groups; group++)
priv->scan_buf.data[group] = tsc2046_adc_get_val(priv, group);
ret = iio_push_to_buffers_with_ts(indio_dev, &priv->scan_buf, sizeof(priv->scan_buf),
iio_get_time_ns(indio_dev)); /* If the consumer is kfifo, we may get a EBUSY here - ignore it. */ if (ret < 0 && ret != -EBUSY) {
dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n",
ERR_PTR(ret));
staticint tsc2046_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m)
{ struct tsc2046_adc_priv *priv = iio_priv(indio_dev); int ret;
switch (m) { case IIO_CHAN_INFO_RAW:
ret = tsc2046_adc_read_one(priv, chan->channel, NULL); if (ret < 0) return ret;
*val = ret;
return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* * Note: the TSC2046 has internal voltage divider on the VBAT * line. This divider can be influenced by external divider. * So, it is better to use external voltage-divider driver * instead, which is calculating complete chain.
*/
*val = priv->vref_mv;
*val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2;
}
if (priv->scan_interval_us < priv->time_per_scan_us)
dev_warn(&priv->spi->dev, "The scan interval (%d) is less then calculated scan time (%d)\n",
priv->scan_interval_us, priv->time_per_scan_us);
/* * This state machine should address following challenges : * - the interrupt source is based on level shifter attached to the X * channel of ADC. It will change the state every time we switch * between channels. So, we need to disable IRQ if we do * iio_trigger_poll(). * - we should do iio_trigger_poll() at some reduced sample rate * - we should still trigger for some amount of time after last * interrupt with enabled IRQ was processed.
*/
spin_lock_irqsave(&priv->state_lock, flags); switch (priv->state) { case TSC2046_STATE_ENABLE_IRQ: if (priv->poll_cnt < TI_TSC2046_POLL_CNT) {
priv->poll_cnt++;
hrtimer_start(&priv->trig_timer,
ns_to_ktime(priv->scan_interval_us *
NSEC_PER_USEC),
HRTIMER_MODE_REL_SOFT);
/* * We can sample it as fast as we can, but usually we do not need so * many samples. Reduce the sample rate for default (touchscreen) use * case.
*/
tim = ns_to_ktime((priv->scan_interval_us - priv->time_per_scan_us) *
NSEC_PER_USEC);
hrtimer_start(&priv->trig_timer, tim, HRTIMER_MODE_REL_SOFT);
}
/* * Make dummy read to set initial power state and get real SPI clock * freq. It seems to be not important which channel is used for this * case.
*/
ret = tsc2046_adc_read_one(priv, TI_TSC2046_ADDR_TEMP0,
&priv->effective_speed_hz); if (ret < 0) return ret;
/* * In case SPI controller do not report effective_speed_hz, use * configure value and hope it will match.
*/ if (!priv->effective_speed_hz)
priv->effective_speed_hz = priv->spi->max_speed_hz;
/* * Calculate and allocate maximal size buffer if all channels are * enabled.
*/
size = 0; for (ch_idx = 0; ch_idx < ARRAY_SIZE(priv->l); ch_idx++)
size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx);
if (size > PAGE_SIZE) {
dev_err(&priv->spi->dev, "Calculated scan buffer is too big. Try to reduce spi-max-frequency, settling-time-us or oversampling-ratio\n"); return -ENOSPC;
}
priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL); if (!priv->tx) return -ENOMEM;
priv->rx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL); if (!priv->rx) return -ENOMEM;
if (spi->max_speed_hz > TI_TSC2046_MAX_CLK_FREQ) {
dev_err(dev, "SPI max_speed_hz is too high: %d Hz. Max supported freq is %zu Hz\n",
spi->max_speed_hz, TI_TSC2046_MAX_CLK_FREQ); return -EINVAL;
}
dcfg = spi_get_device_match_data(spi); if (!dcfg) return -EINVAL;
spi->mode &= ~SPI_MODE_X_MASK;
spi->mode |= SPI_MODE_0;
ret = spi_setup(spi); if (ret < 0) return dev_err_probe(dev, ret, "Error in SPI setup\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM;
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.