xref: /OK3568_Linux_fs/kernel/drivers/iio/accel/da280.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**
3*4882a593Smuzhiyun  * IIO driver for the MiraMEMS DA280 3-axis accelerometer and
4*4882a593Smuzhiyun  * IIO driver for the MiraMEMS DA226 2-axis accelerometer
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/acpi.h>
12*4882a593Smuzhiyun #include <linux/iio/iio.h>
13*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
14*4882a593Smuzhiyun #include <linux/byteorder/generic.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define DA280_REG_CHIP_ID		0x01
17*4882a593Smuzhiyun #define DA280_REG_ACC_X_LSB		0x02
18*4882a593Smuzhiyun #define DA280_REG_ACC_Y_LSB		0x04
19*4882a593Smuzhiyun #define DA280_REG_ACC_Z_LSB		0x06
20*4882a593Smuzhiyun #define DA280_REG_MODE_BW		0x11
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define DA280_CHIP_ID			0x13
23*4882a593Smuzhiyun #define DA280_MODE_ENABLE		0x1e
24*4882a593Smuzhiyun #define DA280_MODE_DISABLE		0x9e
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun enum da280_chipset { da226, da280 };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * a value of + or -4096 corresponds to + or - 1G
30*4882a593Smuzhiyun  * scale = 9.81 / 4096 = 0.002395019
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun static const int da280_nscale = 2395019;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define DA280_CHANNEL(reg, axis) {	\
36*4882a593Smuzhiyun 	.type = IIO_ACCEL,	\
37*4882a593Smuzhiyun 	.address = reg,	\
38*4882a593Smuzhiyun 	.modified = 1,	\
39*4882a593Smuzhiyun 	.channel2 = IIO_MOD_##axis,	\
40*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
41*4882a593Smuzhiyun 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static const struct iio_chan_spec da280_channels[] = {
45*4882a593Smuzhiyun 	DA280_CHANNEL(DA280_REG_ACC_X_LSB, X),
46*4882a593Smuzhiyun 	DA280_CHANNEL(DA280_REG_ACC_Y_LSB, Y),
47*4882a593Smuzhiyun 	DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z),
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun struct da280_data {
51*4882a593Smuzhiyun 	struct i2c_client *client;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
da280_enable(struct i2c_client * client,bool enable)54*4882a593Smuzhiyun static int da280_enable(struct i2c_client *client, bool enable)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	u8 data = enable ? DA280_MODE_ENABLE : DA280_MODE_DISABLE;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return i2c_smbus_write_byte_data(client, DA280_REG_MODE_BW, data);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
da280_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)61*4882a593Smuzhiyun static int da280_read_raw(struct iio_dev *indio_dev,
62*4882a593Smuzhiyun 				struct iio_chan_spec const *chan,
63*4882a593Smuzhiyun 				int *val, int *val2, long mask)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	struct da280_data *data = iio_priv(indio_dev);
66*4882a593Smuzhiyun 	int ret;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	switch (mask) {
69*4882a593Smuzhiyun 	case IIO_CHAN_INFO_RAW:
70*4882a593Smuzhiyun 		ret = i2c_smbus_read_word_data(data->client, chan->address);
71*4882a593Smuzhiyun 		if (ret < 0)
72*4882a593Smuzhiyun 			return ret;
73*4882a593Smuzhiyun 		/*
74*4882a593Smuzhiyun 		 * Values are 14 bits, stored as 16 bits with the 2
75*4882a593Smuzhiyun 		 * least significant bits always 0.
76*4882a593Smuzhiyun 		 */
77*4882a593Smuzhiyun 		*val = (short)ret >> 2;
78*4882a593Smuzhiyun 		return IIO_VAL_INT;
79*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
80*4882a593Smuzhiyun 		*val = 0;
81*4882a593Smuzhiyun 		*val2 = da280_nscale;
82*4882a593Smuzhiyun 		return IIO_VAL_INT_PLUS_NANO;
83*4882a593Smuzhiyun 	default:
84*4882a593Smuzhiyun 		return -EINVAL;
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static const struct iio_info da280_info = {
89*4882a593Smuzhiyun 	.read_raw	= da280_read_raw,
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun 
da280_match_acpi_device(struct device * dev)92*4882a593Smuzhiyun static enum da280_chipset da280_match_acpi_device(struct device *dev)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	const struct acpi_device_id *id;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
97*4882a593Smuzhiyun 	if (!id)
98*4882a593Smuzhiyun 		return -EINVAL;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return (enum da280_chipset) id->driver_data;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
da280_probe(struct i2c_client * client,const struct i2c_device_id * id)103*4882a593Smuzhiyun static int da280_probe(struct i2c_client *client,
104*4882a593Smuzhiyun 			const struct i2c_device_id *id)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	int ret;
107*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
108*4882a593Smuzhiyun 	struct da280_data *data;
109*4882a593Smuzhiyun 	enum da280_chipset chip;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
112*4882a593Smuzhiyun 	if (ret != DA280_CHIP_ID)
113*4882a593Smuzhiyun 		return (ret < 0) ? ret : -ENODEV;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
116*4882a593Smuzhiyun 	if (!indio_dev)
117*4882a593Smuzhiyun 		return -ENOMEM;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	data = iio_priv(indio_dev);
120*4882a593Smuzhiyun 	data->client = client;
121*4882a593Smuzhiyun 	i2c_set_clientdata(client, indio_dev);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	indio_dev->info = &da280_info;
124*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
125*4882a593Smuzhiyun 	indio_dev->channels = da280_channels;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	if (ACPI_HANDLE(&client->dev)) {
128*4882a593Smuzhiyun 		chip = da280_match_acpi_device(&client->dev);
129*4882a593Smuzhiyun 	} else {
130*4882a593Smuzhiyun 		chip = id->driver_data;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (chip == da226) {
134*4882a593Smuzhiyun 		indio_dev->name = "da226";
135*4882a593Smuzhiyun 		indio_dev->num_channels = 2;
136*4882a593Smuzhiyun 	} else {
137*4882a593Smuzhiyun 		indio_dev->name = "da280";
138*4882a593Smuzhiyun 		indio_dev->num_channels = 3;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	ret = da280_enable(client, true);
142*4882a593Smuzhiyun 	if (ret < 0)
143*4882a593Smuzhiyun 		return ret;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	ret = iio_device_register(indio_dev);
146*4882a593Smuzhiyun 	if (ret < 0) {
147*4882a593Smuzhiyun 		dev_err(&client->dev, "device_register failed\n");
148*4882a593Smuzhiyun 		da280_enable(client, false);
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	return ret;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
da280_remove(struct i2c_client * client)154*4882a593Smuzhiyun static int da280_remove(struct i2c_client *client)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	iio_device_unregister(indio_dev);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	return da280_enable(client, false);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
da280_suspend(struct device * dev)164*4882a593Smuzhiyun static int da280_suspend(struct device *dev)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	return da280_enable(to_i2c_client(dev), false);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
da280_resume(struct device * dev)169*4882a593Smuzhiyun static int da280_resume(struct device *dev)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	return da280_enable(to_i2c_client(dev), true);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun static const struct acpi_device_id da280_acpi_match[] = {
178*4882a593Smuzhiyun 	{"MIRAACC", da280},
179*4882a593Smuzhiyun 	{},
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static const struct i2c_device_id da280_i2c_id[] = {
184*4882a593Smuzhiyun 	{ "da226", da226 },
185*4882a593Smuzhiyun 	{ "da280", da280 },
186*4882a593Smuzhiyun 	{}
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun static struct i2c_driver da280_driver = {
191*4882a593Smuzhiyun 	.driver = {
192*4882a593Smuzhiyun 		.name = "da280",
193*4882a593Smuzhiyun 		.acpi_match_table = ACPI_PTR(da280_acpi_match),
194*4882a593Smuzhiyun 		.pm = &da280_pm_ops,
195*4882a593Smuzhiyun 	},
196*4882a593Smuzhiyun 	.probe		= da280_probe,
197*4882a593Smuzhiyun 	.remove		= da280_remove,
198*4882a593Smuzhiyun 	.id_table	= da280_i2c_id,
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun module_i2c_driver(da280_driver);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
204*4882a593Smuzhiyun MODULE_DESCRIPTION("MiraMEMS DA280 3-Axis Accelerometer driver");
205*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
206