[go: nahoru, domu]

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