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