Re: [PATCH v3 3/3] iio: adc: add ADC driver for the TI TSC2046 controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Mar 19, 2021 at 4:45 PM Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> wrote:
>
> Basically the TI TSC2046 touchscreen controller is 8 channel ADC optimized for
> the touchscreen use case. By implementing it as an IIO ADC device, we can
> make use of resistive-adc-touch and iio-hwmon drivers.
>
> So far, this driver was tested with a custom version of resistive-adc-touch driver,
> since it needs to be extended to make use of Z1 and Z2 channels. The X/Y
> are working without additional changes.

Since kbuild bot found some issues and it will be v4, some additional
comments from me below.

...

> +#define        TI_TSC2046_SAMPLE_BITS \
> +       (sizeof(struct tsc2046_adc_atom) * BITS_PER_BYTE)

Isn't it something like BITS_PER_TYPE(struct ...) ?

...

> +struct tsc2046_adc_atom {
> +       /*
> +        * Command transmitted to the controller. This filed is empty on the RX
> +        * buffer.
> +        */
> +       u8 cmd;
> +       /*
> +        * Data received from the controller. This filed is empty for the TX
> +        * buffer
> +        */
> +       __be16 data;
> +} __packed;

filed -> field in both cases above.

...

> +       /*
> +        * Lock to protect the layout and the spi transfer buffer.

SPI

> +        * 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.
> +        */

...

> +static unsigned int tsc2046_adc_time_to_count(struct tsc2046_adc_priv *priv,
> +                                             unsigned long time)
> +{
> +       unsigned int bit_count, sample_count;
> +
> +       bit_count = DIV_ROUND_UP(time * NSEC_PER_USEC, priv->time_per_bit_ns);

Does it survive 32-bit builds?

> +       sample_count = DIV_ROUND_UP(bit_count, TI_TSC2046_SAMPLE_BITS);
> +
> +       dev_dbg(&priv->spi->dev, "Effective speed %u, time per bit: %u, count bits: %u, count samples: %u\n",
> +               priv->effective_speed_hz, priv->time_per_bit_ns,
> +               bit_count, sample_count);
> +
> +       return 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;

Can be ternary on one line, but it's up to you.

...

> +static u16 tsc2046_adc_get_value(struct tsc2046_adc_atom *buf)
> +{
> +       /* Last 3 bits on the wire are empty */

Last?! You meant Least significant?
Also, don't we lose precision if a new compatible chip appears that
does fill those bits?

Perhaps define the constant and put a comment why it's like this.

> +       return get_unaligned_be16(&buf->data) >> 3;
> +}

...

> +static size_t tsc2046_adc_group_set_layout(struct tsc2046_adc_priv *priv,
> +                                          unsigned int group,
> +                                          unsigned int ch_idx)
> +{
> +       struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx];
> +       struct tsc2046_adc_group_layout *prev, *cur;
> +       unsigned int max_count, count_skip;
> +       unsigned int offset = 0;
> +
> +       if (group) {
> +               prev = &priv->l[group - 1];
> +               offset = prev->offset + prev->count;
> +       }

I guess you may easily refactor this by supplying a pointer to the
current layout + current size.

> +       cur = &priv->l[group];

Also, can you move it down closer to the (single?) caller.

> +}

...

> +static int 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 filed: %pe\n",
> +                                   ERR_PTR(ret));

One line?

> +               return ret;
> +       }

> +       ret = iio_push_to_buffers_with_timestamp(indio_dev, &priv->scan_buf,
> +                                                iio_get_time_ns(indio_dev));
> +       /* If consumer is kfifo, we may get a EBUSY here - ignore it. */

the consumer

> +       if (ret < 0 && ret != -EBUSY) {
> +               dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n",
> +                                   ERR_PTR(ret));
> +
> +               return ret;
> +       }
> +
> +       return 0;
> +}


...

> +static enum hrtimer_restart tsc2046_adc_trig_more(struct hrtimer *hrtimer)
> +{
> +       struct tsc2046_adc_priv *priv = container_of(hrtimer,
> +                                                    struct tsc2046_adc_priv,
> +                                                    trig_timer);
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&priv->trig_lock, flags);
> +
> +       disable_irq_nosync(priv->spi->irq);

> +       atomic_inc(&priv->trig_more_count);

You already have a spin lock, do you need to use the atomic API?

> +       iio_trigger_poll(priv->trig);
> +
> +       spin_unlock_irqrestore(&priv->trig_lock, flags);
> +
> +       return HRTIMER_NORESTART;
> +}

...

> +       size_t size = 0;

Move the assignment closer to the actual use of the variable.

...

> +       /*
> +        * In case SPI controller do not report effective_speed_hz, use
> +        * configure value and hope it will match

Missed period.

> +        */
> +       if (!priv->effective_speed_hz)
> +               priv->effective_speed_hz = priv->spi->max_speed_hz;

Also can be ternary on one line, but it's up to you.

...

> +       name = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
> +                             TI_TSC2046_NAME, dev_name(dev));

No NULL check?
Should be added or justified.

...

> +       trig->dev.parent = indio_dev->dev.parent;

Don't we have this done by core (some recent patches in upstream)?

...

> +       ret = devm_iio_device_register(dev, indio_dev);
> +       if (ret) {
> +               dev_err(dev, "Failed to register iio device\n");

> +               return ret;
> +       }
> +
> +       return 0;

  return ret;
or even
  return devm_iio_device_register(dev, indio_dev);

-- 
With Best Regards,
Andy Shevchenko



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux