Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Touchscreen driver for Dialog Semiconductor DA9034
0004  *
0005  * Copyright (C) 2006-2008 Marvell International Ltd.
0006  *  Fengwei Yin <fengwei.yin@marvell.com>
0007  *  Bin Yang  <bin.yang@marvell.com>
0008  *  Eric Miao <eric.miao@marvell.com>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/delay.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/input.h>
0016 #include <linux/workqueue.h>
0017 #include <linux/mfd/da903x.h>
0018 #include <linux/slab.h>
0019 
0020 #define DA9034_MANUAL_CTRL  0x50
0021 #define DA9034_LDO_ADC_EN   (1 << 4)
0022 
0023 #define DA9034_AUTO_CTRL1   0x51
0024 
0025 #define DA9034_AUTO_CTRL2   0x52
0026 #define DA9034_AUTO_TSI_EN  (1 << 3)
0027 #define DA9034_PEN_DETECT   (1 << 4)
0028 
0029 #define DA9034_TSI_CTRL1    0x53
0030 #define DA9034_TSI_CTRL2    0x54
0031 #define DA9034_TSI_X_MSB    0x6c
0032 #define DA9034_TSI_Y_MSB    0x6d
0033 #define DA9034_TSI_XY_LSB   0x6e
0034 
0035 enum {
0036     STATE_IDLE, /* wait for pendown */
0037     STATE_BUSY, /* TSI busy sampling */
0038     STATE_STOP, /* sample available */
0039     STATE_WAIT, /* Wait to start next sample */
0040 };
0041 
0042 enum {
0043     EVENT_PEN_DOWN,
0044     EVENT_PEN_UP,
0045     EVENT_TSI_READY,
0046     EVENT_TIMEDOUT,
0047 };
0048 
0049 struct da9034_touch {
0050     struct device       *da9034_dev;
0051     struct input_dev    *input_dev;
0052 
0053     struct delayed_work tsi_work;
0054     struct notifier_block   notifier;
0055 
0056     int state;
0057 
0058     int interval_ms;
0059     int x_inverted;
0060     int y_inverted;
0061 
0062     int last_x;
0063     int last_y;
0064 };
0065 
0066 static inline int is_pen_down(struct da9034_touch *touch)
0067 {
0068     return da903x_query_status(touch->da9034_dev, DA9034_STATUS_PEN_DOWN);
0069 }
0070 
0071 static inline int detect_pen_down(struct da9034_touch *touch, int on)
0072 {
0073     if (on)
0074         return da903x_set_bits(touch->da9034_dev,
0075                 DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
0076     else
0077         return da903x_clr_bits(touch->da9034_dev,
0078                 DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
0079 }
0080 
0081 static int read_tsi(struct da9034_touch *touch)
0082 {
0083     uint8_t _x, _y, _v;
0084     int ret;
0085 
0086     ret = da903x_read(touch->da9034_dev, DA9034_TSI_X_MSB, &_x);
0087     if (ret)
0088         return ret;
0089 
0090     ret = da903x_read(touch->da9034_dev, DA9034_TSI_Y_MSB, &_y);
0091     if (ret)
0092         return ret;
0093 
0094     ret = da903x_read(touch->da9034_dev, DA9034_TSI_XY_LSB, &_v);
0095     if (ret)
0096         return ret;
0097 
0098     touch->last_x = ((_x << 2) & 0x3fc) | (_v & 0x3);
0099     touch->last_y = ((_y << 2) & 0x3fc) | ((_v & 0xc) >> 2);
0100 
0101     return 0;
0102 }
0103 
0104 static inline int start_tsi(struct da9034_touch *touch)
0105 {
0106     return da903x_set_bits(touch->da9034_dev,
0107             DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
0108 }
0109 
0110 static inline int stop_tsi(struct da9034_touch *touch)
0111 {
0112     return da903x_clr_bits(touch->da9034_dev,
0113             DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
0114 }
0115 
0116 static inline void report_pen_down(struct da9034_touch *touch)
0117 {
0118     int x = touch->last_x;
0119     int y = touch->last_y;
0120 
0121     x &= 0xfff;
0122     if (touch->x_inverted)
0123         x = 1024 - x;
0124     y &= 0xfff;
0125     if (touch->y_inverted)
0126         y = 1024 - y;
0127 
0128     input_report_abs(touch->input_dev, ABS_X, x);
0129     input_report_abs(touch->input_dev, ABS_Y, y);
0130     input_report_key(touch->input_dev, BTN_TOUCH, 1);
0131 
0132     input_sync(touch->input_dev);
0133 }
0134 
0135 static inline void report_pen_up(struct da9034_touch *touch)
0136 {
0137     input_report_key(touch->input_dev, BTN_TOUCH, 0);
0138     input_sync(touch->input_dev);
0139 }
0140 
0141 static void da9034_event_handler(struct da9034_touch *touch, int event)
0142 {
0143     int err;
0144 
0145     switch (touch->state) {
0146     case STATE_IDLE:
0147         if (event != EVENT_PEN_DOWN)
0148             break;
0149 
0150         /* Enable auto measurement of the TSI, this will
0151          * automatically disable pen down detection
0152          */
0153         err = start_tsi(touch);
0154         if (err)
0155             goto err_reset;
0156 
0157         touch->state = STATE_BUSY;
0158         break;
0159 
0160     case STATE_BUSY:
0161         if (event != EVENT_TSI_READY)
0162             break;
0163 
0164         err = read_tsi(touch);
0165         if (err)
0166             goto err_reset;
0167 
0168         /* Disable auto measurement of the TSI, so that
0169          * pen down status will be available
0170          */
0171         err = stop_tsi(touch);
0172         if (err)
0173             goto err_reset;
0174 
0175         touch->state = STATE_STOP;
0176 
0177         /* FIXME: PEN_{UP/DOWN} events are expected to be
0178          * available by stopping TSI, but this is found not
0179          * always true, delay and simulate such an event
0180          * here is more reliable
0181          */
0182         mdelay(1);
0183         da9034_event_handler(touch,
0184                      is_pen_down(touch) ? EVENT_PEN_DOWN :
0185                               EVENT_PEN_UP);
0186         break;
0187 
0188     case STATE_STOP:
0189         if (event == EVENT_PEN_DOWN) {
0190             report_pen_down(touch);
0191             schedule_delayed_work(&touch->tsi_work,
0192                 msecs_to_jiffies(touch->interval_ms));
0193             touch->state = STATE_WAIT;
0194         }
0195 
0196         if (event == EVENT_PEN_UP) {
0197             report_pen_up(touch);
0198             touch->state = STATE_IDLE;
0199         }
0200         break;
0201 
0202     case STATE_WAIT:
0203         if (event != EVENT_TIMEDOUT)
0204             break;
0205 
0206         if (is_pen_down(touch)) {
0207             start_tsi(touch);
0208             touch->state = STATE_BUSY;
0209         } else {
0210             report_pen_up(touch);
0211             touch->state = STATE_IDLE;
0212         }
0213         break;
0214     }
0215     return;
0216 
0217 err_reset:
0218     touch->state = STATE_IDLE;
0219     stop_tsi(touch);
0220     detect_pen_down(touch, 1);
0221 }
0222 
0223 static void da9034_tsi_work(struct work_struct *work)
0224 {
0225     struct da9034_touch *touch =
0226         container_of(work, struct da9034_touch, tsi_work.work);
0227 
0228     da9034_event_handler(touch, EVENT_TIMEDOUT);
0229 }
0230 
0231 static int da9034_touch_notifier(struct notifier_block *nb,
0232                  unsigned long event, void *data)
0233 {
0234     struct da9034_touch *touch =
0235         container_of(nb, struct da9034_touch, notifier);
0236 
0237     if (event & DA9034_EVENT_TSI_READY)
0238         da9034_event_handler(touch, EVENT_TSI_READY);
0239 
0240     if ((event & DA9034_EVENT_PEN_DOWN) && touch->state == STATE_IDLE)
0241         da9034_event_handler(touch, EVENT_PEN_DOWN);
0242 
0243     return 0;
0244 }
0245 
0246 static int da9034_touch_open(struct input_dev *dev)
0247 {
0248     struct da9034_touch *touch = input_get_drvdata(dev);
0249     int ret;
0250 
0251     ret = da903x_register_notifier(touch->da9034_dev, &touch->notifier,
0252             DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
0253     if (ret)
0254         return -EBUSY;
0255 
0256     /* Enable ADC LDO */
0257     ret = da903x_set_bits(touch->da9034_dev,
0258             DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
0259     if (ret)
0260         return ret;
0261 
0262     /* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
0263     ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL1, 0x1b);
0264     if (ret)
0265         return ret;
0266 
0267     ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL2, 0x00);
0268     if (ret)
0269         return ret;
0270 
0271     touch->state = STATE_IDLE;
0272     detect_pen_down(touch, 1);
0273 
0274     return 0;
0275 }
0276 
0277 static void da9034_touch_close(struct input_dev *dev)
0278 {
0279     struct da9034_touch *touch = input_get_drvdata(dev);
0280 
0281     da903x_unregister_notifier(touch->da9034_dev, &touch->notifier,
0282             DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
0283 
0284     cancel_delayed_work_sync(&touch->tsi_work);
0285 
0286     touch->state = STATE_IDLE;
0287     stop_tsi(touch);
0288     detect_pen_down(touch, 0);
0289 
0290     /* Disable ADC LDO */
0291     da903x_clr_bits(touch->da9034_dev,
0292             DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
0293 }
0294 
0295 
0296 static int da9034_touch_probe(struct platform_device *pdev)
0297 {
0298     struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
0299     struct da9034_touch *touch;
0300     struct input_dev *input_dev;
0301     int error;
0302 
0303     touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
0304                  GFP_KERNEL);
0305     if (!touch) {
0306         dev_err(&pdev->dev, "failed to allocate driver data\n");
0307         return -ENOMEM;
0308     }
0309 
0310     touch->da9034_dev = pdev->dev.parent;
0311 
0312     if (pdata) {
0313         touch->interval_ms  = pdata->interval_ms;
0314         touch->x_inverted   = pdata->x_inverted;
0315         touch->y_inverted   = pdata->y_inverted;
0316     } else {
0317         /* fallback into default */
0318         touch->interval_ms  = 10;
0319     }
0320 
0321     INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
0322     touch->notifier.notifier_call = da9034_touch_notifier;
0323 
0324     input_dev = devm_input_allocate_device(&pdev->dev);
0325     if (!input_dev) {
0326         dev_err(&pdev->dev, "failed to allocate input device\n");
0327         return -ENOMEM;
0328     }
0329 
0330     input_dev->name     = pdev->name;
0331     input_dev->open     = da9034_touch_open;
0332     input_dev->close    = da9034_touch_close;
0333     input_dev->dev.parent   = &pdev->dev;
0334 
0335     __set_bit(EV_ABS, input_dev->evbit);
0336     __set_bit(ABS_X, input_dev->absbit);
0337     __set_bit(ABS_Y, input_dev->absbit);
0338     input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
0339     input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
0340 
0341     __set_bit(EV_KEY, input_dev->evbit);
0342     __set_bit(BTN_TOUCH, input_dev->keybit);
0343 
0344     touch->input_dev = input_dev;
0345     input_set_drvdata(input_dev, touch);
0346 
0347     error = input_register_device(input_dev);
0348     if (error)
0349         return error;
0350 
0351     return 0;
0352 }
0353 
0354 static struct platform_driver da9034_touch_driver = {
0355     .driver = {
0356         .name   = "da9034-touch",
0357     },
0358     .probe      = da9034_touch_probe,
0359 };
0360 module_platform_driver(da9034_touch_driver);
0361 
0362 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
0363 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
0364 MODULE_LICENSE("GPL");
0365 MODULE_ALIAS("platform:da9034-touch");