linux/drivers/input/joystick/as5011.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
   4 * Sponsored by ARMadeus Systems
   5 *
   6 * Driver for Austria Microsystems joysticks AS5011
   7 *
   8 * TODO:
   9 *      - Power on the chip when open() and power down when close()
  10 *      - Manage power mode
  11 */
  12
  13#include <linux/i2c.h>
  14#include <linux/interrupt.h>
  15#include <linux/input.h>
  16#include <linux/gpio.h>
  17#include <linux/delay.h>
  18#include <linux/input/as5011.h>
  19#include <linux/slab.h>
  20#include <linux/module.h>
  21
  22#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick"
  23#define MODULE_DEVICE_ALIAS "as5011"
  24
  25MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>");
  26MODULE_DESCRIPTION(DRIVER_DESC);
  27MODULE_LICENSE("GPL");
  28
  29/* registers */
  30#define AS5011_CTRL1            0x76
  31#define AS5011_CTRL2            0x75
  32#define AS5011_XP               0x43
  33#define AS5011_XN               0x44
  34#define AS5011_YP               0x53
  35#define AS5011_YN               0x54
  36#define AS5011_X_REG            0x41
  37#define AS5011_Y_REG            0x42
  38#define AS5011_X_RES_INT        0x51
  39#define AS5011_Y_RES_INT        0x52
  40
  41/* CTRL1 bits */
  42#define AS5011_CTRL1_LP_PULSED          0x80
  43#define AS5011_CTRL1_LP_ACTIVE          0x40
  44#define AS5011_CTRL1_LP_CONTINUE        0x20
  45#define AS5011_CTRL1_INT_WUP_EN         0x10
  46#define AS5011_CTRL1_INT_ACT_EN         0x08
  47#define AS5011_CTRL1_EXT_CLK_EN         0x04
  48#define AS5011_CTRL1_SOFT_RST           0x02
  49#define AS5011_CTRL1_DATA_VALID         0x01
  50
  51/* CTRL2 bits */
  52#define AS5011_CTRL2_EXT_SAMPLE_EN      0x08
  53#define AS5011_CTRL2_RC_BIAS_ON         0x04
  54#define AS5011_CTRL2_INV_SPINNING       0x02
  55
  56#define AS5011_MAX_AXIS 80
  57#define AS5011_MIN_AXIS (-80)
  58#define AS5011_FUZZ     8
  59#define AS5011_FLAT     40
  60
  61struct as5011_device {
  62        struct input_dev *input_dev;
  63        struct i2c_client *i2c_client;
  64        unsigned int button_gpio;
  65        unsigned int button_irq;
  66        unsigned int axis_irq;
  67};
  68
  69static int as5011_i2c_write(struct i2c_client *client,
  70                            uint8_t aregaddr,
  71                            uint8_t avalue)
  72{
  73        uint8_t data[2] = { aregaddr, avalue };
  74        struct i2c_msg msg = {
  75                .addr = client->addr,
  76                .flags = I2C_M_IGNORE_NAK,
  77                .len = 2,
  78                .buf = (uint8_t *)data
  79        };
  80        int error;
  81
  82        error = i2c_transfer(client->adapter, &msg, 1);
  83        return error < 0 ? error : 0;
  84}
  85
  86static int as5011_i2c_read(struct i2c_client *client,
  87                           uint8_t aregaddr, signed char *value)
  88{
  89        uint8_t data[2] = { aregaddr };
  90        struct i2c_msg msg_set[2] = {
  91                {
  92                        .addr = client->addr,
  93                        .flags = I2C_M_REV_DIR_ADDR,
  94                        .len = 1,
  95                        .buf = (uint8_t *)data
  96                },
  97                {
  98                        .addr = client->addr,
  99                        .flags = I2C_M_RD | I2C_M_NOSTART,
 100                        .len = 1,
 101                        .buf = (uint8_t *)data
 102                }
 103        };
 104        int error;
 105
 106        error = i2c_transfer(client->adapter, msg_set, 2);
 107        if (error < 0)
 108                return error;
 109
 110        *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0];
 111        return 0;
 112}
 113
 114static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
 115{
 116        struct as5011_device *as5011 = dev_id;
 117        int val = gpio_get_value_cansleep(as5011->button_gpio);
 118
 119        input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
 120        input_sync(as5011->input_dev);
 121
 122        return IRQ_HANDLED;
 123}
 124
 125static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id)
 126{
 127        struct as5011_device *as5011 = dev_id;
 128        int error;
 129        signed char x, y;
 130
 131        error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x);
 132        if (error < 0)
 133                goto out;
 134
 135        error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y);
 136        if (error < 0)
 137                goto out;
 138
 139        input_report_abs(as5011->input_dev, ABS_X, x);
 140        input_report_abs(as5011->input_dev, ABS_Y, y);
 141        input_sync(as5011->input_dev);
 142
 143out:
 144        return IRQ_HANDLED;
 145}
 146
 147static int as5011_configure_chip(struct as5011_device *as5011,
 148                                const struct as5011_platform_data *plat_dat)
 149{
 150        struct i2c_client *client = as5011->i2c_client;
 151        int error;
 152        signed char value;
 153
 154        /* chip soft reset */
 155        error = as5011_i2c_write(client, AS5011_CTRL1,
 156                                 AS5011_CTRL1_SOFT_RST);
 157        if (error < 0) {
 158                dev_err(&client->dev, "Soft reset failed\n");
 159                return error;
 160        }
 161
 162        mdelay(10);
 163
 164        error = as5011_i2c_write(client, AS5011_CTRL1,
 165                                 AS5011_CTRL1_LP_PULSED |
 166                                 AS5011_CTRL1_LP_ACTIVE |
 167                                 AS5011_CTRL1_INT_ACT_EN);
 168        if (error < 0) {
 169                dev_err(&client->dev, "Power config failed\n");
 170                return error;
 171        }
 172
 173        error = as5011_i2c_write(client, AS5011_CTRL2,
 174                                 AS5011_CTRL2_INV_SPINNING);
 175        if (error < 0) {
 176                dev_err(&client->dev, "Can't invert spinning\n");
 177                return error;
 178        }
 179
 180        /* write threshold */
 181        error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp);
 182        if (error < 0) {
 183                dev_err(&client->dev, "Can't write threshold\n");
 184                return error;
 185        }
 186
 187        error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn);
 188        if (error < 0) {
 189                dev_err(&client->dev, "Can't write threshold\n");
 190                return error;
 191        }
 192
 193        error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp);
 194        if (error < 0) {
 195                dev_err(&client->dev, "Can't write threshold\n");
 196                return error;
 197        }
 198
 199        error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn);
 200        if (error < 0) {
 201                dev_err(&client->dev, "Can't write threshold\n");
 202                return error;
 203        }
 204
 205        /* to free irq gpio in chip */
 206        error = as5011_i2c_read(client, AS5011_X_RES_INT, &value);
 207        if (error < 0) {
 208                dev_err(&client->dev, "Can't read i2c X resolution value\n");
 209                return error;
 210        }
 211
 212        return 0;
 213}
 214
 215static int as5011_probe(struct i2c_client *client,
 216                         const struct i2c_device_id *id)
 217{
 218        const struct as5011_platform_data *plat_data;
 219        struct as5011_device *as5011;
 220        struct input_dev *input_dev;
 221        int irq;
 222        int error;
 223
 224        plat_data = dev_get_platdata(&client->dev);
 225        if (!plat_data)
 226                return -EINVAL;
 227
 228        if (!plat_data->axis_irq) {
 229                dev_err(&client->dev, "No axis IRQ?\n");
 230                return -EINVAL;
 231        }
 232
 233        if (!i2c_check_functionality(client->adapter,
 234                                     I2C_FUNC_NOSTART |
 235                                     I2C_FUNC_PROTOCOL_MANGLING)) {
 236                dev_err(&client->dev,
 237                        "need i2c bus that supports protocol mangling\n");
 238                return -ENODEV;
 239        }
 240
 241        as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
 242        input_dev = input_allocate_device();
 243        if (!as5011 || !input_dev) {
 244                dev_err(&client->dev,
 245                        "Can't allocate memory for device structure\n");
 246                error = -ENOMEM;
 247                goto err_free_mem;
 248        }
 249
 250        as5011->i2c_client = client;
 251        as5011->input_dev = input_dev;
 252        as5011->button_gpio = plat_data->button_gpio;
 253        as5011->axis_irq = plat_data->axis_irq;
 254
 255        input_dev->name = "Austria Microsystem as5011 joystick";
 256        input_dev->id.bustype = BUS_I2C;
 257        input_dev->dev.parent = &client->dev;
 258
 259        input_set_capability(input_dev, EV_KEY, BTN_JOYSTICK);
 260
 261        input_set_abs_params(input_dev, ABS_X,
 262                AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
 263        input_set_abs_params(as5011->input_dev, ABS_Y,
 264                AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
 265
 266        error = gpio_request(as5011->button_gpio, "AS5011 button");
 267        if (error < 0) {
 268                dev_err(&client->dev, "Failed to request button gpio\n");
 269                goto err_free_mem;
 270        }
 271
 272        irq = gpio_to_irq(as5011->button_gpio);
 273        if (irq < 0) {
 274                dev_err(&client->dev,
 275                        "Failed to get irq number for button gpio\n");
 276                error = irq;
 277                goto err_free_button_gpio;
 278        }
 279
 280        as5011->button_irq = irq;
 281
 282        error = request_threaded_irq(as5011->button_irq,
 283                                     NULL, as5011_button_interrupt,
 284                                     IRQF_TRIGGER_RISING |
 285                                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 286                                     "as5011_button", as5011);
 287        if (error < 0) {
 288                dev_err(&client->dev,
 289                        "Can't allocate button irq %d\n", as5011->button_irq);
 290                goto err_free_button_gpio;
 291        }
 292
 293        error = as5011_configure_chip(as5011, plat_data);
 294        if (error)
 295                goto err_free_button_irq;
 296
 297        error = request_threaded_irq(as5011->axis_irq, NULL,
 298                                     as5011_axis_interrupt,
 299                                     plat_data->axis_irqflags | IRQF_ONESHOT,
 300                                     "as5011_joystick", as5011);
 301        if (error) {
 302                dev_err(&client->dev,
 303                        "Can't allocate axis irq %d\n", plat_data->axis_irq);
 304                goto err_free_button_irq;
 305        }
 306
 307        error = input_register_device(as5011->input_dev);
 308        if (error) {
 309                dev_err(&client->dev, "Failed to register input device\n");
 310                goto err_free_axis_irq;
 311        }
 312
 313        i2c_set_clientdata(client, as5011);
 314
 315        return 0;
 316
 317err_free_axis_irq:
 318        free_irq(as5011->axis_irq, as5011);
 319err_free_button_irq:
 320        free_irq(as5011->button_irq, as5011);
 321err_free_button_gpio:
 322        gpio_free(as5011->button_gpio);
 323err_free_mem:
 324        input_free_device(input_dev);
 325        kfree(as5011);
 326
 327        return error;
 328}
 329
 330static int as5011_remove(struct i2c_client *client)
 331{
 332        struct as5011_device *as5011 = i2c_get_clientdata(client);
 333
 334        free_irq(as5011->axis_irq, as5011);
 335        free_irq(as5011->button_irq, as5011);
 336        gpio_free(as5011->button_gpio);
 337
 338        input_unregister_device(as5011->input_dev);
 339        kfree(as5011);
 340
 341        return 0;
 342}
 343
 344static const struct i2c_device_id as5011_id[] = {
 345        { MODULE_DEVICE_ALIAS, 0 },
 346        { }
 347};
 348MODULE_DEVICE_TABLE(i2c, as5011_id);
 349
 350static struct i2c_driver as5011_driver = {
 351        .driver = {
 352                .name = "as5011",
 353        },
 354        .probe          = as5011_probe,
 355        .remove         = as5011_remove,
 356        .id_table       = as5011_id,
 357};
 358
 359module_i2c_driver(as5011_driver);
 360