19d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau/* 29d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com> 39d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * Sponsored by ARMadeus Systems 49d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * 59d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * This program is free software; you can redistribute it and/or modify 69d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * it under the terms of the GNU General Public License as published by 79d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * the Free Software Foundation; either version 2 of the License, or 89d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * (at your option) any later version. 99d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * 109d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * This program is distributed in the hope that it will be useful, 119d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * but WITHOUT ANY WARRANTY; without even the implied warranty of 129d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 139d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * GNU General Public License for more details. 149d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * 159d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * You should have received a copy of the GNU General Public License 169d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * along with this program; if not, write to the Free Software 179d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 189d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * 199d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * Driver for Austria Microsystems joysticks AS5011 209d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * 219d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * TODO: 229d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * - Power on the chip when open() and power down when close() 239d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau * - Manage power mode 249d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau */ 259d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 269d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/i2c.h> 279d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/interrupt.h> 289d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/input.h> 299d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/gpio.h> 309d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/delay.h> 319d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/input/as5011.h> 329d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#include <linux/slab.h> 33d2d8442d0094a7d4b585e2bbde31e3775dba7eb1Paul Gortmaker#include <linux/module.h> 349d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 359d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick" 369d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define MODULE_DEVICE_ALIAS "as5011" 379d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 389d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien MarteauMODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>"); 399d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien MarteauMODULE_DESCRIPTION(DRIVER_DESC); 409d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien MarteauMODULE_LICENSE("GPL"); 419d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 429d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau/* registers */ 439d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1 0x76 449d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL2 0x75 459d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_XP 0x43 469d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_XN 0x44 479d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_YP 0x53 489d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_YN 0x54 499d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_X_REG 0x41 509d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_Y_REG 0x42 519d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_X_RES_INT 0x51 529d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_Y_RES_INT 0x52 539d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 549d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau/* CTRL1 bits */ 559d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_LP_PULSED 0x80 569d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_LP_ACTIVE 0x40 579d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_LP_CONTINUE 0x20 589d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_INT_WUP_EN 0x10 599d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_INT_ACT_EN 0x08 609d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_EXT_CLK_EN 0x04 619d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_SOFT_RST 0x02 629d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL1_DATA_VALID 0x01 639d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 649d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau/* CTRL2 bits */ 659d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08 669d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL2_RC_BIAS_ON 0x04 679d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_CTRL2_INV_SPINNING 0x02 689d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 699d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_MAX_AXIS 80 709d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_MIN_AXIS (-80) 719d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_FUZZ 8 729d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau#define AS5011_FLAT 40 739d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 749d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustruct as5011_device { 759d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct input_dev *input_dev; 769d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct i2c_client *i2c_client; 779d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau unsigned int button_gpio; 789d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau unsigned int button_irq; 799d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau unsigned int axis_irq; 809d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau}; 819d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 829d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic int as5011_i2c_write(struct i2c_client *client, 839d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau uint8_t aregaddr, 849d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau uint8_t avalue) 859d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 869d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau uint8_t data[2] = { aregaddr, avalue }; 879d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct i2c_msg msg = { 8824e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .addr = client->addr, 8924e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .flags = I2C_M_IGNORE_NAK, 9024e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .len = 2, 9124e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .buf = (uint8_t *)data 929d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau }; 939d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int error; 949d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 959d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = i2c_transfer(client->adapter, &msg, 1); 969d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error < 0 ? error : 0; 979d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 989d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 999d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic int as5011_i2c_read(struct i2c_client *client, 1009d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau uint8_t aregaddr, signed char *value) 1019d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 1029d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau uint8_t data[2] = { aregaddr }; 1039d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct i2c_msg msg_set[2] = { 10424e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D { 10524e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .addr = client->addr, 10624e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .flags = I2C_M_REV_DIR_ADDR, 10724e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .len = 1, 10824e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .buf = (uint8_t *)data 10924e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D }, 11024e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D { 11124e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .addr = client->addr, 11224e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .flags = I2C_M_RD | I2C_M_NOSTART, 11324e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .len = 1, 11424e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D .buf = (uint8_t *)data 11524e491c21b4e214a980a5daf2a5bc80e8c410ce6Shubhrajyoti D } 1169d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau }; 1179d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int error; 1189d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1199d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = i2c_transfer(client->adapter, msg_set, 2); 1209d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) 1219d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 1229d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1239d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0]; 1249d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return 0; 1259d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 1269d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1279d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic irqreturn_t as5011_button_interrupt(int irq, void *dev_id) 1289d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 1299d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct as5011_device *as5011 = dev_id; 1309d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int val = gpio_get_value_cansleep(as5011->button_gpio); 1319d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1329d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_report_key(as5011->input_dev, BTN_JOYSTICK, !val); 1339d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_sync(as5011->input_dev); 1349d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1359d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return IRQ_HANDLED; 1369d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 1379d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1389d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic irqreturn_t as5011_axis_interrupt(int irq, void *dev_id) 1399d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 1409d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct as5011_device *as5011 = dev_id; 1419d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int error; 1429d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau signed char x, y; 1439d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1449d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x); 1459d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) 1469d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto out; 1479d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1489d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y); 1499d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) 1509d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto out; 1519d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1529d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_report_abs(as5011->input_dev, ABS_X, x); 1539d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_report_abs(as5011->input_dev, ABS_Y, y); 1549d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_sync(as5011->input_dev); 1559d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1569d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteauout: 1579d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return IRQ_HANDLED; 1589d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 1599d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1605298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int as5011_configure_chip(struct as5011_device *as5011, 1619d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau const struct as5011_platform_data *plat_dat) 1629d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 1639d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct i2c_client *client = as5011->i2c_client; 1649d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int error; 1659d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau signed char value; 1669d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1679d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau /* chip soft reset */ 1689d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_CTRL1, 1699d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_CTRL1_SOFT_RST); 1709d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 1719d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Soft reset failed\n"); 1729d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 1739d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 1749d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1759d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau mdelay(10); 1769d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1779d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_CTRL1, 1789d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_CTRL1_LP_PULSED | 1799d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_CTRL1_LP_ACTIVE | 1809d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_CTRL1_INT_ACT_EN); 1819d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 1829d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Power config failed\n"); 1839d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 1849d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 1859d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1869d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_CTRL2, 1879d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_CTRL2_INV_SPINNING); 1889d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 1899d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't invert spinning\n"); 1909d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 1919d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 1929d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 1939d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau /* write threshold */ 1949d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp); 1959d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 1969d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't write threshold\n"); 1979d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 1989d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 1999d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2009d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn); 2019d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 2029d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't write threshold\n"); 2039d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 2049d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2059d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2069d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp); 2079d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 2089d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't write threshold\n"); 2099d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 2109d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2119d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2129d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn); 2139d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 2149d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't write threshold\n"); 2159d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 2169d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2179d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2189d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau /* to free irq gpio in chip */ 2199d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_i2c_read(client, AS5011_X_RES_INT, &value); 2209d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 2219d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Can't read i2c X resolution value\n"); 2229d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 2239d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2249d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2259d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return 0; 2269d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 2279d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2285298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int as5011_probe(struct i2c_client *client, 2295298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pemberton const struct i2c_device_id *id) 2309d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 2319d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau const struct as5011_platform_data *plat_data; 2329d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct as5011_device *as5011; 2339d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct input_dev *input_dev; 2349d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int irq; 2359d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau int error; 2369d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 237846fc20ff76ae10793c0f02b67f0308234fb7539Jingoo Han plat_data = dev_get_platdata(&client->dev); 2389d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (!plat_data) 2399d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return -EINVAL; 2409d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2419d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (!plat_data->axis_irq) { 2429d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "No axis IRQ?\n"); 2439d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return -EINVAL; 2449d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2459d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2469d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (!i2c_check_functionality(client->adapter, 24714674e70119ea01549ce593d8901a797f8a90f74Mark Brown I2C_FUNC_NOSTART | 2489d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau I2C_FUNC_PROTOCOL_MANGLING)) { 2499d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, 2509d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "need i2c bus that supports protocol mangling\n"); 2519d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return -ENODEV; 2529d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2539d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2549d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL); 2559d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_dev = input_allocate_device(); 2569d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (!as5011 || !input_dev) { 2579d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, 2589d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "Can't allocate memory for device structure\n"); 2599d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = -ENOMEM; 2609d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_mem; 2619d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2629d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2639d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011->i2c_client = client; 2649d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011->input_dev = input_dev; 2659d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011->button_gpio = plat_data->button_gpio; 2669d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011->axis_irq = plat_data->axis_irq; 2679d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2689d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_dev->name = "Austria Microsystem as5011 joystick"; 2699d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_dev->id.bustype = BUS_I2C; 2709d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_dev->dev.parent = &client->dev; 2719d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2729d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau __set_bit(EV_KEY, input_dev->evbit); 2739d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau __set_bit(EV_ABS, input_dev->evbit); 2749d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau __set_bit(BTN_JOYSTICK, input_dev->keybit); 2759d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2769d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_set_abs_params(input_dev, ABS_X, 2779d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); 2789d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_set_abs_params(as5011->input_dev, ABS_Y, 2799d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); 2809d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2819d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = gpio_request(as5011->button_gpio, "AS5011 button"); 2829d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 2839d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Failed to request button gpio\n"); 2849d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_mem; 2859d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2869d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2879d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau irq = gpio_to_irq(as5011->button_gpio); 2889d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (irq < 0) { 2899d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, 2909d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "Failed to get irq number for button gpio\n"); 29167b3bfd0c22274f1b3c40f0820cbdc1d71f7d0cdWei Yongjun error = irq; 2929d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_button_gpio; 2939d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 2949d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2959d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011->button_irq = irq; 2969d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 2979d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = request_threaded_irq(as5011->button_irq, 2989d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau NULL, as5011_button_interrupt, 2999b7e31bbf4bb58b12e11a7f24b7c3e48bbd2f4daLars-Peter Clausen IRQF_TRIGGER_RISING | 3009b7e31bbf4bb58b12e11a7f24b7c3e48bbd2f4daLars-Peter Clausen IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 3019d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "as5011_button", as5011); 3029d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error < 0) { 3039d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, 3049d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "Can't allocate button irq %d\n", as5011->button_irq); 3059d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_button_gpio; 3069d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 3079d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3089d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = as5011_configure_chip(as5011, plat_data); 3099d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error) 3109d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_button_irq; 3119d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3129d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = request_threaded_irq(as5011->axis_irq, NULL, 3139d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau as5011_axis_interrupt, 3149b7e31bbf4bb58b12e11a7f24b7c3e48bbd2f4daLars-Peter Clausen plat_data->axis_irqflags | IRQF_ONESHOT, 3159d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "as5011_joystick", as5011); 3169d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error) { 3179d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, 3189d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau "Can't allocate axis irq %d\n", plat_data->axis_irq); 3199d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_button_irq; 3209d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 3219d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3229d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau error = input_register_device(as5011->input_dev); 3239d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau if (error) { 3249d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau dev_err(&client->dev, "Failed to register input device\n"); 3259d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau goto err_free_axis_irq; 3269d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau } 3279d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3289d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau i2c_set_clientdata(client, as5011); 3299d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3309d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return 0; 3319d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3329d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteauerr_free_axis_irq: 3339d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau free_irq(as5011->axis_irq, as5011); 3349d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteauerr_free_button_irq: 3359d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau free_irq(as5011->button_irq, as5011); 3369d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteauerr_free_button_gpio: 3379d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau gpio_free(as5011->button_gpio); 3389d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteauerr_free_mem: 3399d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_free_device(input_dev); 3409d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau kfree(as5011); 3419d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3429d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return error; 3439d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 3449d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 345e2619cf78e19476bfd7ceaefa9eff0847529346eBill Pembertonstatic int as5011_remove(struct i2c_client *client) 3469d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau{ 3479d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau struct as5011_device *as5011 = i2c_get_clientdata(client); 3489d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3499d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau free_irq(as5011->axis_irq, as5011); 3509d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau free_irq(as5011->button_irq, as5011); 3519d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau gpio_free(as5011->button_gpio); 3529d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3539d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau input_unregister_device(as5011->input_dev); 3549d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau kfree(as5011); 3559d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3569d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau return 0; 3579d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau} 3589d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3599d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic const struct i2c_device_id as5011_id[] = { 3609d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau { MODULE_DEVICE_ALIAS, 0 }, 3619d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau { } 3629d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau}; 3639d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien MarteauMODULE_DEVICE_TABLE(i2c, as5011_id); 3649d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3659d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteaustatic struct i2c_driver as5011_driver = { 3669d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau .driver = { 3679d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau .name = "as5011", 3689d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau }, 3699d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau .probe = as5011_probe, 3701cb0aa88179b7a71c240529e9d781d7bbb43d2e8Bill Pemberton .remove = as5011_remove, 3719d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau .id_table = as5011_id, 3729d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau}; 3739d084a3d5dffd076a9a006164ea0dbd9c495f2b0Fabien Marteau 3741b92c1cf6b638e7cbe9fdaac3f6efb8874f5cc02Axel Linmodule_i2c_driver(as5011_driver); 375