1 // SPDX-License-Identifier: GPL-2.0-only
3 * MXC6255 - MEMSIC orientation sensing accelerometer
5 * Copyright (c) 2015, Intel Corporation.
7 * IIO driver for MXC6255 (7-bit I2C slave address 0x15).
10 #include <linux/module.h>
11 #include <linux/i2c.h>
12 #include <linux/init.h>
13 #include <linux/iio/iio.h>
14 #include <linux/delay.h>
15 #include <linux/acpi.h>
16 #include <linux/regmap.h>
17 #include <linux/iio/sysfs.h>
19 #define MXC6255_DRV_NAME "mxc6255"
20 #define MXC6255_REGMAP_NAME "mxc6255_regmap"
22 #define MXC6255_REG_XOUT 0x00
23 #define MXC6255_REG_YOUT 0x01
24 #define MXC6255_REG_CHIP_ID 0x08
26 #define MXC6255_CHIP_ID 0x05
29 * MXC6255 has only one measurement range: +/- 2G.
30 * The acceleration output is an 8-bit value.
32 * Scale is calculated as follows:
33 * (2 + 2) * 9.80665 / (2^8 - 1) = 0.153829
35 * Scale value for +/- 2G measurement range
37 #define MXC6255_SCALE 153829
45 struct i2c_client
*client
;
46 struct regmap
*regmap
;
49 static int mxc6255_read_raw(struct iio_dev
*indio_dev
,
50 struct iio_chan_spec
const *chan
,
51 int *val
, int *val2
, long mask
)
53 struct mxc6255_data
*data
= iio_priv(indio_dev
);
58 case IIO_CHAN_INFO_RAW
:
59 ret
= regmap_read(data
->regmap
, chan
->address
, ®
);
61 dev_err(&data
->client
->dev
,
62 "Error reading reg %lu\n", chan
->address
);
66 *val
= sign_extend32(reg
, 7);
68 case IIO_CHAN_INFO_SCALE
:
70 *val2
= MXC6255_SCALE
;
71 return IIO_VAL_INT_PLUS_MICRO
;
77 static const struct iio_info mxc6255_info
= {
78 .read_raw
= mxc6255_read_raw
,
81 #define MXC6255_CHANNEL(_axis, reg) { \
84 .channel2 = IIO_MOD_##_axis, \
86 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
87 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
90 static const struct iio_chan_spec mxc6255_channels
[] = {
91 MXC6255_CHANNEL(X
, MXC6255_REG_XOUT
),
92 MXC6255_CHANNEL(Y
, MXC6255_REG_YOUT
),
95 static bool mxc6255_is_readable_reg(struct device
*dev
, unsigned int reg
)
98 case MXC6255_REG_XOUT
:
99 case MXC6255_REG_YOUT
:
100 case MXC6255_REG_CHIP_ID
:
107 static const struct regmap_config mxc6255_regmap_config
= {
108 .name
= MXC6255_REGMAP_NAME
,
113 .readable_reg
= mxc6255_is_readable_reg
,
116 static int mxc6255_probe(struct i2c_client
*client
,
117 const struct i2c_device_id
*id
)
119 struct mxc6255_data
*data
;
120 struct iio_dev
*indio_dev
;
121 struct regmap
*regmap
;
122 unsigned int chip_id
;
125 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
129 regmap
= devm_regmap_init_i2c(client
, &mxc6255_regmap_config
);
130 if (IS_ERR(regmap
)) {
131 dev_err(&client
->dev
, "Error initializing regmap\n");
132 return PTR_ERR(regmap
);
135 data
= iio_priv(indio_dev
);
136 i2c_set_clientdata(client
, indio_dev
);
137 data
->client
= client
;
138 data
->regmap
= regmap
;
140 indio_dev
->name
= MXC6255_DRV_NAME
;
141 indio_dev
->dev
.parent
= &client
->dev
;
142 indio_dev
->channels
= mxc6255_channels
;
143 indio_dev
->num_channels
= ARRAY_SIZE(mxc6255_channels
);
144 indio_dev
->modes
= INDIO_DIRECT_MODE
;
145 indio_dev
->info
= &mxc6255_info
;
147 ret
= regmap_read(data
->regmap
, MXC6255_REG_CHIP_ID
, &chip_id
);
149 dev_err(&client
->dev
, "Error reading chip id %d\n", ret
);
153 if ((chip_id
& 0x1f) != MXC6255_CHIP_ID
) {
154 dev_err(&client
->dev
, "Invalid chip id %x\n", chip_id
);
158 dev_dbg(&client
->dev
, "Chip id %x\n", chip_id
);
160 ret
= devm_iio_device_register(&client
->dev
, indio_dev
);
162 dev_err(&client
->dev
, "Could not register IIO device\n");
169 static const struct acpi_device_id mxc6255_acpi_match
[] = {
174 MODULE_DEVICE_TABLE(acpi
, mxc6255_acpi_match
);
176 static const struct i2c_device_id mxc6255_id
[] = {
181 MODULE_DEVICE_TABLE(i2c
, mxc6255_id
);
183 static struct i2c_driver mxc6255_driver
= {
185 .name
= MXC6255_DRV_NAME
,
186 .acpi_match_table
= ACPI_PTR(mxc6255_acpi_match
),
188 .probe
= mxc6255_probe
,
189 .id_table
= mxc6255_id
,
192 module_i2c_driver(mxc6255_driver
);
194 MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
195 MODULE_DESCRIPTION("MEMSIC MXC6255 orientation sensing accelerometer driver");
196 MODULE_LICENSE("GPL v2");