Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * TSI driver for Dialog DA9052
0004  *
0005  * Copyright(c) 2012 Dialog Semiconductor Ltd.
0006  *
0007  * Author: David Dajun Chen <dchen@diasemi.com>
0008  */
0009 #include <linux/module.h>
0010 #include <linux/input.h>
0011 #include <linux/delay.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/interrupt.h>
0014 
0015 #include <linux/mfd/da9052/reg.h>
0016 #include <linux/mfd/da9052/da9052.h>
0017 
0018 #define TSI_PEN_DOWN_STATUS 0x40
0019 
0020 struct da9052_tsi {
0021     struct da9052 *da9052;
0022     struct input_dev *dev;
0023     struct delayed_work ts_pen_work;
0024     bool stopped;
0025     bool adc_on;
0026 };
0027 
0028 static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
0029 {
0030     da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
0031     tsi->adc_on = on;
0032 }
0033 
0034 static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
0035 {
0036     struct da9052_tsi *tsi = data;
0037 
0038     if (!tsi->stopped) {
0039         /* Mask PEN_DOWN event and unmask TSI_READY event */
0040         da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN);
0041         da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
0042 
0043         da9052_ts_adc_toggle(tsi, true);
0044 
0045         schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
0046     }
0047 
0048     return IRQ_HANDLED;
0049 }
0050 
0051 static void da9052_ts_read(struct da9052_tsi *tsi)
0052 {
0053     struct input_dev *input = tsi->dev;
0054     int ret;
0055     u16 x, y, z;
0056     u8 v;
0057 
0058     ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
0059     if (ret < 0)
0060         return;
0061 
0062     x = (u16) ret;
0063 
0064     ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
0065     if (ret < 0)
0066         return;
0067 
0068     y = (u16) ret;
0069 
0070     ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
0071     if (ret < 0)
0072         return;
0073 
0074     z = (u16) ret;
0075 
0076     ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
0077     if (ret < 0)
0078         return;
0079 
0080     v = (u8) ret;
0081 
0082     x = ((x << 2) & 0x3fc) | (v & 0x3);
0083     y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
0084     z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
0085 
0086     input_report_key(input, BTN_TOUCH, 1);
0087     input_report_abs(input, ABS_X, x);
0088     input_report_abs(input, ABS_Y, y);
0089     input_report_abs(input, ABS_PRESSURE, z);
0090     input_sync(input);
0091 }
0092 
0093 static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
0094 {
0095     struct da9052_tsi *tsi = data;
0096 
0097     da9052_ts_read(tsi);
0098 
0099     return IRQ_HANDLED;
0100 }
0101 
0102 static void da9052_ts_pen_work(struct work_struct *work)
0103 {
0104     struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
0105                           ts_pen_work.work);
0106     if (!tsi->stopped) {
0107         int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
0108         if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
0109             /* Pen is still DOWN (or read error) */
0110             schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
0111         } else {
0112             struct input_dev *input = tsi->dev;
0113 
0114             /* Pen UP */
0115             da9052_ts_adc_toggle(tsi, false);
0116 
0117             /* Report Pen UP */
0118             input_report_key(input, BTN_TOUCH, 0);
0119             input_report_abs(input, ABS_PRESSURE, 0);
0120             input_sync(input);
0121 
0122             /*
0123              * FIXME: Fixes the unhandled irq issue when quick
0124              * pen down and pen up events occurs
0125              */
0126             ret = da9052_reg_update(tsi->da9052,
0127                         DA9052_EVENT_B_REG, 0xC0, 0xC0);
0128             if (ret < 0)
0129                 return;
0130 
0131             /* Mask TSI_READY event and unmask PEN_DOWN event */
0132             da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
0133             da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
0134         }
0135     }
0136 }
0137 
0138 static int da9052_ts_configure_gpio(struct da9052 *da9052)
0139 {
0140     int error;
0141 
0142     error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
0143     if (error < 0)
0144         return error;
0145 
0146     error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
0147     if (error < 0)
0148         return error;
0149 
0150     error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
0151     if (error < 0)
0152         return error;
0153 
0154     return 0;
0155 }
0156 
0157 static int da9052_configure_tsi(struct da9052_tsi *tsi)
0158 {
0159     int error;
0160 
0161     error = da9052_ts_configure_gpio(tsi->da9052);
0162     if (error)
0163         return error;
0164 
0165     /* Measure TSI sample every 1ms */
0166     error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
0167                   1 << 6, 1 << 6);
0168     if (error < 0)
0169         return error;
0170 
0171     /* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
0172     error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
0173     if (error < 0)
0174         return error;
0175 
0176     /* Supply TSIRef through LD09 */
0177     error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
0178     if (error < 0)
0179         return error;
0180 
0181     return 0;
0182 }
0183 
0184 static int da9052_ts_input_open(struct input_dev *input_dev)
0185 {
0186     struct da9052_tsi *tsi = input_get_drvdata(input_dev);
0187 
0188     tsi->stopped = false;
0189     mb();
0190 
0191     /* Unmask PEN_DOWN event */
0192     da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
0193 
0194     /* Enable Pen Detect Circuit */
0195     return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
0196                  1 << 1, 1 << 1);
0197 }
0198 
0199 static void da9052_ts_input_close(struct input_dev *input_dev)
0200 {
0201     struct da9052_tsi *tsi = input_get_drvdata(input_dev);
0202 
0203     tsi->stopped = true;
0204     mb();
0205     da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
0206     cancel_delayed_work_sync(&tsi->ts_pen_work);
0207 
0208     if (tsi->adc_on) {
0209         da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
0210         da9052_ts_adc_toggle(tsi, false);
0211 
0212         /*
0213          * If ADC was on that means that pendwn IRQ was disabled
0214          * twice and we need to enable it to keep enable/disable
0215          * counter balanced. IRQ is still off though.
0216          */
0217         da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
0218     }
0219 
0220     /* Disable Pen Detect Circuit */
0221     da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
0222 }
0223 
0224 static int da9052_ts_probe(struct platform_device *pdev)
0225 {
0226     struct da9052 *da9052;
0227     struct da9052_tsi *tsi;
0228     struct input_dev *input_dev;
0229     int error;
0230 
0231     da9052 = dev_get_drvdata(pdev->dev.parent);
0232     if (!da9052)
0233         return -EINVAL;
0234 
0235     tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
0236     input_dev = input_allocate_device();
0237     if (!tsi || !input_dev) {
0238         error = -ENOMEM;
0239         goto err_free_mem;
0240     }
0241 
0242     tsi->da9052 = da9052;
0243     tsi->dev = input_dev;
0244     tsi->stopped = true;
0245     INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
0246 
0247     input_dev->id.version = 0x0101;
0248     input_dev->id.vendor = 0x15B6;
0249     input_dev->id.product = 0x9052;
0250     input_dev->name = "Dialog DA9052 TouchScreen Driver";
0251     input_dev->dev.parent = &pdev->dev;
0252     input_dev->open = da9052_ts_input_open;
0253     input_dev->close = da9052_ts_input_close;
0254 
0255     __set_bit(EV_ABS, input_dev->evbit);
0256     __set_bit(EV_KEY, input_dev->evbit);
0257     __set_bit(BTN_TOUCH, input_dev->keybit);
0258 
0259     input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
0260     input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
0261     input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
0262 
0263     input_set_drvdata(input_dev, tsi);
0264 
0265     /* Disable Pen Detect Circuit */
0266     da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
0267 
0268     /* Disable ADC */
0269     da9052_ts_adc_toggle(tsi, false);
0270 
0271     error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN,
0272                 "pendown-irq", da9052_ts_pendwn_irq, tsi);
0273     if (error) {
0274         dev_err(tsi->da9052->dev,
0275             "Failed to register PENDWN IRQ: %d\n", error);
0276         goto err_free_mem;
0277     }
0278 
0279     error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY,
0280                 "tsiready-irq", da9052_ts_datardy_irq, tsi);
0281     if (error) {
0282         dev_err(tsi->da9052->dev,
0283             "Failed to register TSIRDY IRQ :%d\n", error);
0284         goto err_free_pendwn_irq;
0285     }
0286 
0287     /* Mask PEN_DOWN and TSI_READY events */
0288     da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
0289     da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
0290 
0291     error = da9052_configure_tsi(tsi);
0292     if (error)
0293         goto err_free_datardy_irq;
0294 
0295     error = input_register_device(tsi->dev);
0296     if (error)
0297         goto err_free_datardy_irq;
0298 
0299     platform_set_drvdata(pdev, tsi);
0300 
0301     return 0;
0302 
0303 err_free_datardy_irq:
0304     da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
0305 err_free_pendwn_irq:
0306     da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
0307 err_free_mem:
0308     kfree(tsi);
0309     input_free_device(input_dev);
0310 
0311     return error;
0312 }
0313 
0314 static int  da9052_ts_remove(struct platform_device *pdev)
0315 {
0316     struct da9052_tsi *tsi = platform_get_drvdata(pdev);
0317 
0318     da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
0319 
0320     da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
0321     da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
0322 
0323     input_unregister_device(tsi->dev);
0324     kfree(tsi);
0325 
0326     return 0;
0327 }
0328 
0329 static struct platform_driver da9052_tsi_driver = {
0330     .probe  = da9052_ts_probe,
0331     .remove = da9052_ts_remove,
0332     .driver = {
0333         .name   = "da9052-tsi",
0334     },
0335 };
0336 
0337 module_platform_driver(da9052_tsi_driver);
0338 
0339 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
0340 MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
0341 MODULE_LICENSE("GPL");
0342 MODULE_ALIAS("platform:da9052-tsi");