Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Touchscreen driver for the TS-4800 board
0003  *
0004  * Copyright (c) 2015 - Savoir-faire Linux
0005  *
0006  * This file is licensed under the terms of the GNU General Public
0007  * License version 2. This program is licensed "as is" without any
0008  * warranty of any kind, whether express or implied.
0009  */
0010 
0011 #include <linux/bitops.h>
0012 #include <linux/input.h>
0013 #include <linux/io.h>
0014 #include <linux/kernel.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/regmap.h>
0020 
0021 /* polling interval in ms */
0022 #define POLL_INTERVAL       3
0023 
0024 #define DEBOUNCE_COUNT      1
0025 
0026 /* sensor values are 12-bit wide */
0027 #define MAX_12BIT       ((1 << 12) - 1)
0028 
0029 #define PENDOWN_MASK        0x1
0030 
0031 #define X_OFFSET        0x0
0032 #define Y_OFFSET        0x2
0033 
0034 struct ts4800_ts {
0035     struct input_dev        *input;
0036     struct device           *dev;
0037     char                    phys[32];
0038 
0039     void __iomem            *base;
0040     struct regmap           *regmap;
0041     unsigned int            reg;
0042     unsigned int            bit;
0043 
0044     bool                    pendown;
0045     int                     debounce;
0046 };
0047 
0048 static int ts4800_ts_open(struct input_dev *input_dev)
0049 {
0050     struct ts4800_ts *ts = input_get_drvdata(input_dev);
0051     int error;
0052 
0053     ts->pendown = false;
0054     ts->debounce = DEBOUNCE_COUNT;
0055 
0056     error = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
0057     if (error) {
0058         dev_warn(ts->dev, "Failed to enable touchscreen: %d\n", error);
0059         return error;
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static void ts4800_ts_close(struct input_dev *input_dev)
0066 {
0067     struct ts4800_ts *ts = input_get_drvdata(input_dev);
0068     int ret;
0069 
0070     ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
0071     if (ret)
0072         dev_warn(ts->dev, "Failed to disable touchscreen\n");
0073 
0074 }
0075 
0076 static void ts4800_ts_poll(struct input_dev *input_dev)
0077 {
0078     struct ts4800_ts *ts = input_get_drvdata(input_dev);
0079     u16 last_x = readw(ts->base + X_OFFSET);
0080     u16 last_y = readw(ts->base + Y_OFFSET);
0081     bool pendown = last_x & PENDOWN_MASK;
0082 
0083     if (pendown) {
0084         if (ts->debounce) {
0085             ts->debounce--;
0086             return;
0087         }
0088 
0089         if (!ts->pendown) {
0090             input_report_key(input_dev, BTN_TOUCH, 1);
0091             ts->pendown = true;
0092         }
0093 
0094         last_x = ((~last_x) >> 4) & MAX_12BIT;
0095         last_y = ((~last_y) >> 4) & MAX_12BIT;
0096 
0097         input_report_abs(input_dev, ABS_X, last_x);
0098         input_report_abs(input_dev, ABS_Y, last_y);
0099         input_sync(input_dev);
0100     } else if (ts->pendown) {
0101         ts->pendown = false;
0102         ts->debounce = DEBOUNCE_COUNT;
0103         input_report_key(input_dev, BTN_TOUCH, 0);
0104         input_sync(input_dev);
0105     }
0106 }
0107 
0108 static int ts4800_parse_dt(struct platform_device *pdev,
0109                struct ts4800_ts *ts)
0110 {
0111     struct device *dev = &pdev->dev;
0112     struct device_node *np = dev->of_node;
0113     struct device_node *syscon_np;
0114     u32 reg, bit;
0115     int error;
0116 
0117     syscon_np = of_parse_phandle(np, "syscon", 0);
0118     if (!syscon_np) {
0119         dev_err(dev, "no syscon property\n");
0120         return -ENODEV;
0121     }
0122 
0123     ts->regmap = syscon_node_to_regmap(syscon_np);
0124     of_node_put(syscon_np);
0125     if (IS_ERR(ts->regmap)) {
0126         dev_err(dev, "cannot get parent's regmap\n");
0127         return PTR_ERR(ts->regmap);
0128     }
0129 
0130     error = of_property_read_u32_index(np, "syscon", 1, &reg);
0131     if (error < 0) {
0132         dev_err(dev, "no offset in syscon\n");
0133         return error;
0134     }
0135 
0136     ts->reg = reg;
0137 
0138     error = of_property_read_u32_index(np, "syscon", 2, &bit);
0139     if (error < 0) {
0140         dev_err(dev, "no bit in syscon\n");
0141         return error;
0142     }
0143 
0144     ts->bit = BIT(bit);
0145 
0146     return 0;
0147 }
0148 
0149 static int ts4800_ts_probe(struct platform_device *pdev)
0150 {
0151     struct input_dev *input_dev;
0152     struct ts4800_ts *ts;
0153     int error;
0154 
0155     ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
0156     if (!ts)
0157         return -ENOMEM;
0158 
0159     error = ts4800_parse_dt(pdev, ts);
0160     if (error)
0161         return error;
0162 
0163     ts->base = devm_platform_ioremap_resource(pdev, 0);
0164     if (IS_ERR(ts->base))
0165         return PTR_ERR(ts->base);
0166 
0167     input_dev = devm_input_allocate_device(&pdev->dev);
0168     if (!input_dev)
0169         return -ENOMEM;
0170 
0171     snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
0172     ts->input = input_dev;
0173     ts->dev = &pdev->dev;
0174 
0175     input_set_drvdata(input_dev, ts);
0176 
0177     input_dev->name = "TS-4800 Touchscreen";
0178     input_dev->phys = ts->phys;
0179 
0180     input_dev->open = ts4800_ts_open;
0181     input_dev->close = ts4800_ts_close;
0182 
0183     input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
0184     input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
0185     input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
0186 
0187     error = input_setup_polling(input_dev, ts4800_ts_poll);
0188     if (error) {
0189         dev_err(&pdev->dev, "Unable to set up polling: %d\n", error);
0190         return error;
0191     }
0192 
0193     input_set_poll_interval(input_dev, POLL_INTERVAL);
0194 
0195     error = input_register_device(input_dev);
0196     if (error) {
0197         dev_err(&pdev->dev,
0198             "Unable to register input device: %d\n", error);
0199         return error;
0200     }
0201 
0202     return 0;
0203 }
0204 
0205 static const struct of_device_id ts4800_ts_of_match[] = {
0206     { .compatible = "technologic,ts4800-ts", },
0207     { },
0208 };
0209 MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
0210 
0211 static struct platform_driver ts4800_ts_driver = {
0212     .driver = {
0213         .name = "ts4800-ts",
0214         .of_match_table = ts4800_ts_of_match,
0215     },
0216     .probe = ts4800_ts_probe,
0217 };
0218 module_platform_driver(ts4800_ts_driver);
0219 
0220 MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
0221 MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
0222 MODULE_LICENSE("GPL v2");
0223 MODULE_ALIAS("platform:ts4800_ts");