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