Re: [PATCH v4] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens

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

 



Hi Dmitry,

Thank you for your comments and I'm sorry for my late reply.

2015-01-15 10:35 GMT+09:00 Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>:
> Hi Yoichi,
>
> On Fri, Dec 05, 2014 at 06:17:39PM +0900, Yoichi Yuasa wrote:
>> v4 Changes:
>> - remove inline
>> - master_xfer checks in probe()
>> - rewrite rohm_i2c_burst_read()
>> - rohm_i2c_burst_read() transfer error returns -EIO
>> - remove unused module parameters
>> - fix prev_touch_report update
>> - pass NULL to hard_irq
>> - per-device parameters use sysfs
>> - fix errno
>> - header file is taken in .c
>
> Sorry I missed your V4 update....
>
...
>> +
>> +struct rohm_ts_data {
>> +     struct i2c_client *client;
>> +     struct input_dev *input_dev;
>> +
>> +     bool initialized;
>> +
>> +     unsigned int untouch_count;
>> +     unsigned int single_touch_count;
>> +     unsigned int dual_touch_count;
>
> Hmm, OK, so I guess the screen is very bouncy, that is why you need
> this. I think it should be an array of contact_count[MAX_CONTACTS + 1];
> and then you can do:
>
>         if (ts->finger_count != finger_count) {
>                 memset(ts->contact_count, 0, sizeof(ts->contact_count));
>                 ts->finger_count = finger_count;
>         } else {
>                 ts->contact_count[finger_count]++;
>         }

Ok, I'll update it.

>> +     unsigned int prev_touch_report;
>> +
>> +     u8 setup2;
>> +};
>> +
>> +/*
>> + * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24
>> + * @client: Handle to ROHM BU21023/24
>> + * @start: Where to start read address from ROHM BU21023/24
>> + * @buf: Where to store read data from ROHM BU21023/24
>> + * @len: How many bytes to read
>> + *
>> + * Returns negative errno, else zero on success.
>> + *
>> + * Note
>> + * In BU21023/24 burst read, stop condition is needed after "address write".
>> + * Therefore, transmission is performed in 2 steps.
>
> Is it in errata? I glanced through
> http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/touch_screen/bu21023gul-e.pdf
> and I do not see it mentioned there...

I have no information about errata.
I have only sample code that based of rohm_i2c_burst_read().

In addition, I tried normal burst read, but it didn't work on the device.

>> +
>> +#define READ_CALIB_BUF(reg)  ((u16)buf[((reg) - PRM1_X_H)])
>
> This should be get_unaligned_xx() or xx_to_cpu() to make sure it works
> on all architectures.

The cast can be removed, just remove it

>> +static unsigned int untouch_threshold[3] = { 0, 1, 5 };
>> +static unsigned int single_touch_threshold[3] = { 0, 0, 4 };
>> +static unsigned int dual_touch_threshold[3] = { 10, 8, 0 };
>> +
>> +module_param_array(untouch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
>> +module_param_array(single_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
>> +module_param_array(dual_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
>> +
>> +MODULE_PARM_DESC(untouch_threshold, "Thresholds for un-touch detection");
>> +MODULE_PARM_DESC(single_touch_threshold,
>> +              "Thresholds for single touch detection");
>> +MODULE_PARM_DESC(dual_touch_threshold, "Thresholds for dual touch detection");
>
> DO we really need this as module parameters? Is it user preference or
> something that vendor would set for their device? I.e. maybe it belongs
> to the platform/devicetree data, along with the swaping x/y support?

OK, I remove them.

>> +#define READ_POS_BUF(reg)    ((u16)buf[((reg) - POS_X1_H)])
>
> This should be get_unaligned_xx() or xx_to_cpu() to make sure it works
> on all architectures.

The cast can be removed, just remove it

>> +
>> +     ret = rohm_i2c_burst_read(client, POS_X1_H, buf, sizeof(buf));
>> +     if (ret < 0)
>> +             return IRQ_HANDLED;
>> +
>> +     touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK;
>> +     if (touch_flags) {
>> +             /* generate coordinates */
>> +             pos[0].x = (READ_POS_BUF(POS_X1_H) << 2) |
>> +                        READ_POS_BUF(POS_X1_L);
>> +             pos[0].y = (READ_POS_BUF(POS_Y1_H) << 2) |
>> +                        READ_POS_BUF(POS_Y1_L);
>> +             pos[1].x = (READ_POS_BUF(POS_X2_H) << 2) |
>> +                        READ_POS_BUF(POS_X2_L);
>> +             pos[1].y = (READ_POS_BUF(POS_Y2_H) << 2) |
>> +                        READ_POS_BUF(POS_Y2_L);
>> +
>> +             switch (touch_flags) {
>> +             case SINGLE_TOUCH:
>> +                     ts->untouch_count = 0;
>> +                     ts->single_touch_count++;
>> +                     ts->dual_touch_count = 0;
>> +
>> +                     threshold = single_touch_threshold[prev_touch_report];
>> +                     if (ts->single_touch_count > threshold)
>> +                             touch_report = 1;
>> +
>> +                     if (touch_report == 1) {
>> +                             if (pos[1].x != 0 && pos[1].y != 0) {
>> +                                     pos[0].x = pos[1].x;
>> +                                     pos[0].y = pos[1].y;
>> +                                     pos[1].x = 0;
>> +                                     pos[1].y = 0;
>> +                             }
>> +                     }
>> +                     break;
>> +             case DUAL_TOUCH:
>> +                     ts->untouch_count = 0;
>> +                     ts->single_touch_count = 0;
>> +                     ts->dual_touch_count++;
>> +
>> +                     threshold = dual_touch_threshold[prev_touch_report];
>> +                     if (ts->dual_touch_count > threshold)
>> +                             touch_report = 2;
>> +                     break;
>> +             default:
>> +                     dev_dbg(dev,
>> +                             "Three or more touches are not supported\n");
>> +                     return IRQ_HANDLED;
>> +             }
>> +     } else {
>> +             ts->untouch_count++;
>> +
>> +             threshold = untouch_threshold[prev_touch_report];
>> +             if (ts->untouch_count > threshold) {
>> +                     ts->untouch_count = 0;
>> +                     ts->single_touch_count = 0;
>> +                     ts->dual_touch_count = 0;
>> +
>> +                     touch_report = 0;
>> +             }
>
> Why do we handle "no fingers" separately? Can't we add 'case 0' to the
> switch statement above?

OK, I'll update it.

>> +static int rohm_ts_device_init(struct rohm_ts_data *ts)
>> +{
>> +     struct i2c_client *client = ts->client;
>> +     struct device *dev = &client->dev;
>> +     int ret;
>> +
>> +     /*
>> +      * Wait 200usec for reset
>> +      */
>> +     udelay(200);
>> +
>> +     /* Release analog reset */
>> +     ret = i2c_smbus_write_byte_data(client, SYSTEM, ANALOG_POWER_ON);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Waiting for the analog warm-up, max. 200usec */
>> +     udelay(200);
>> +
>> +     /* clear all interrupts */
>> +     ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, EX_WDAT, 0);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, COMMON_SETUP2, ts->setup2);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, COMMON_SETUP3,
>> +                                     SEL_TBL_DEFAULT | EN_MULTI);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE,
>> +                                     THRESHOLD_GESTURE_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, INTERVAL_TIME,
>> +                                     INTERVAL_TIME_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME,
>> +                                     PRM_SWOFF_TIME_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /*
>> +      * Panel setup, these values change with the panel.
>> +      */
>> +     ret = i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH,
>> +                                     THRESHOLD_TOUCH_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Fixed value settings */
>> +     ret = i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST,
>> +                                     CALIBRATION_ADJUST_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, TEST1,
>> +                                     DUALTOUCH_STABILIZE_ON |
>> +                                     DUALTOUCH_REG_ON);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME);
>> +     if (ret) {
>> +             dev_err(dev, "Failed to firmware load\n");
>> +             return ret;
>> +     }
>> +
>> +     /*
>> +      * Manual calibration results are not changed in same environment.
>> +      * If the force calibration is performed,
>> +      * the controller will not require calibration request interrupt
>> +      * when the typical values are set to the calibration registers.
>> +      */
>> +     ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
>> +                                     CALIBRATION_REG1_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
>> +                                     CALIBRATION_REG2_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
>> +                                     CALIBRATION_REG3_DEFAULT);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
>> +                                     FORCE_CALIBRATION_OFF);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
>> +                                     FORCE_CALIBRATION_ON);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Clear all interrupts */
>> +     ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = devm_request_threaded_irq(dev, client->irq, NULL,
>> +                                     rohm_ts_soft_irq, IRQF_TRIGGER_FALLING,
>> +                                     client->name, ts);
>> +     if (ret) {
>> +             dev_err(dev, "Unable to request IRQ\n");
>> +             return ret;
>> +     }
>
> Preference for interrupts (and other resources) to be requested at probe
> time and just power the device down so it does not generate interrupts
> until somebody opens it.

OK, I'll update it.

>> +
>> +static int rohm_bu21023_i2c_remove(struct i2c_client *client)
>> +{
>> +     int ret;
>> +
>> +     sysfs_remove_group(&client->dev.kobj, &rohm_ts_attr_group);
>> +
>> +     ret = i2c_smbus_write_byte_data(client, SYSTEM,
>> +                                     ANALOG_POWER_ON | CPU_POWER_OFF);
>
> I wonder if this should be done in close() method.

OK, I'll update it too.

I'll send the v5 patch soon.

Thanks,

Yoichi
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux