Skip to content

Commit e0d842a

Browse files
Tooniisminlexx
authored andcommitted
WIP: iio: accel: Add driver for Qualcomm Sensor Manager accelerometers
Add a driver for accelerometers provided by the Qualcomm Sensor Manager service.
1 parent a9bebb4 commit e0d842a

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

drivers/iio/accel/Kconfig

+10
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,16 @@ config IIO_CROS_EC_ACCEL_LEGACY
380380
Sensor data is retrieved through IO memory.
381381
Newer devices should use IIO_CROS_EC_SENSORS.
382382

383+
config IIO_QCOM_SMGR_ACCEL
384+
tristate "Qualcomm SSC Sensor Manager Accelerometer Sensor"
385+
depends on IIO_QCOM_SMGR
386+
select IIO_BUFFER
387+
select IIO_KFIFO_BUF
388+
help
389+
Say yes here to get support for accelerometers connected to
390+
a Qualcomm Snapdragon Sensor Core and accessed through its
391+
Sensor Manager service.
392+
383393
config IIO_ST_ACCEL_3AXIS
384394
tristate "STMicroelectronics accelerometers 3-Axis Driver"
385395
depends on (I2C || SPI_MASTER) && SYSFS

drivers/iio/accel/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ obj-$(CONFIG_STK8BA50) += stk8ba50.o
7575

7676
obj-$(CONFIG_IIO_CROS_EC_ACCEL_LEGACY) += cros_ec_accel_legacy.o
7777

78+
obj-$(CONFIG_IIO_QCOM_SMGR_ACCEL) += smgr_accel.o
79+
7880
obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
7981

8082
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o

drivers/iio/accel/smgr_accel.c

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Qualcomm Sensor Manager accelerometer driver
4+
*
5+
* Copyright (c) 2022, Yassine Oudjana <y.oudjana@protonmail.com>
6+
*/
7+
8+
#include <linux/mod_devicetable.h>
9+
#include <linux/platform_device.h>
10+
#include <linux/iio/buffer.h>
11+
#include <linux/iio/common/qcom_smgr.h>
12+
#include <linux/iio/iio.h>
13+
#include <linux/iio/kfifo_buf.h>
14+
15+
static int smgr_accel_read_raw(struct iio_dev *iio_dev,
16+
struct iio_chan_spec const *chan, int *val,
17+
int *val2, long mask)
18+
{
19+
struct smgr_iio_priv *priv = iio_priv(iio_dev);
20+
21+
switch (mask) {
22+
case IIO_CHAN_INFO_SAMP_FREQ:
23+
*val = priv->sensor->data_types[0].cur_sample_rate;
24+
return IIO_VAL_INT;
25+
case IIO_CHAN_INFO_SCALE:
26+
/*
27+
* TODO: Find out if the scale is standard across devices or
28+
* find a way to get the correct scale for a device
29+
*
30+
* Device reports around 640000 when axis is aligned with
31+
* gravity, therefore scale is 9.81m/s^2 / 640000.
32+
*/
33+
*val = 0;
34+
*val2 = 15328; /* scale * 10^9 */
35+
return IIO_VAL_INT_PLUS_NANO;
36+
}
37+
38+
return -EINVAL;
39+
}
40+
41+
static int smgr_accel_write_raw(struct iio_dev *iio_dev,
42+
struct iio_chan_spec const *chan, int val,
43+
int val2, long mask)
44+
{
45+
struct smgr_iio_priv *priv = iio_priv(iio_dev);
46+
47+
switch (mask) {
48+
case IIO_CHAN_INFO_SAMP_FREQ:
49+
priv->sensor->data_types[0].cur_sample_rate = val;
50+
51+
/*
52+
* Send new SMGR buffering request with updated rates
53+
* if buffer is enabled
54+
*/
55+
if (iio_buffer_enabled(iio_dev))
56+
return iio_dev->setup_ops->postenable(iio_dev);
57+
58+
return 0;
59+
}
60+
61+
return -EINVAL;
62+
}
63+
64+
static int smgr_accel_read_avail(struct iio_dev *iio_dev,
65+
struct iio_chan_spec const *chan,
66+
const int **vals, int *type, int *length,
67+
long mask)
68+
{
69+
struct smgr_iio_priv *priv = iio_priv(iio_dev);
70+
const int samp_freq_vals[3] = {
71+
1, 1, priv->sensor->data_types[0].max_sample_rate
72+
};
73+
74+
switch (mask) {
75+
case IIO_CHAN_INFO_SAMP_FREQ:
76+
*type = IIO_VAL_INT;
77+
*vals = samp_freq_vals;
78+
*length = ARRAY_SIZE(samp_freq_vals);
79+
return IIO_AVAIL_RANGE;
80+
}
81+
82+
return -EINVAL;
83+
}
84+
85+
static const struct iio_info smgr_accel_iio_info = {
86+
.read_raw = smgr_accel_read_raw,
87+
.write_raw = smgr_accel_write_raw,
88+
.read_avail = smgr_accel_read_avail,
89+
};
90+
91+
/* TODO: Get mount matrix from SSC or read it from the device tree */
92+
static const struct iio_mount_matrix qcom_ssc_mount_matrix = {
93+
.rotation = {
94+
"0", "-1", "0",
95+
"-1", "0", "0",
96+
"0", "0", "1"
97+
}
98+
};
99+
100+
static const struct iio_mount_matrix *
101+
smgr_accel_get_mount_matrix(const struct iio_dev *iio_dev,
102+
const struct iio_chan_spec *chan)
103+
{
104+
return &qcom_ssc_mount_matrix;
105+
}
106+
107+
static const struct iio_chan_spec_ext_info smgr_accel_ext_info[] = {
108+
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, smgr_accel_get_mount_matrix),
109+
{}
110+
};
111+
112+
static const struct iio_chan_spec smgr_accel_iio_channels[] = {
113+
{
114+
.type = IIO_ACCEL,
115+
.modified = true,
116+
.channel2 = IIO_MOD_X,
117+
.scan_index = 0,
118+
.scan_type = {
119+
.sign = 's',
120+
.realbits = 24,
121+
.storagebits = 32,
122+
.endianness = IIO_LE,
123+
},
124+
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
125+
BIT(IIO_CHAN_INFO_SAMP_FREQ),
126+
.ext_info = smgr_accel_ext_info
127+
},
128+
{
129+
.type = IIO_ACCEL,
130+
.modified = true,
131+
.channel2 = IIO_MOD_Y,
132+
.scan_index = 1,
133+
.scan_type = {
134+
.sign = 's',
135+
.realbits = 24,
136+
.storagebits = 32,
137+
.endianness = IIO_LE,
138+
},
139+
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
140+
BIT(IIO_CHAN_INFO_SAMP_FREQ),
141+
.ext_info = smgr_accel_ext_info
142+
},
143+
{
144+
.type = IIO_ACCEL,
145+
.modified = true,
146+
.channel2 = IIO_MOD_Z,
147+
.scan_index = 2,
148+
.scan_type = {
149+
.sign = 's',
150+
.realbits = 24,
151+
.storagebits = 32,
152+
.endianness = IIO_LE,
153+
},
154+
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
155+
BIT(IIO_CHAN_INFO_SAMP_FREQ),
156+
.ext_info = smgr_accel_ext_info
157+
},
158+
{
159+
.type = IIO_TIMESTAMP,
160+
.channel = -1,
161+
.scan_index = 3,
162+
.scan_type = {
163+
.sign = 'u',
164+
.realbits = 32,
165+
.storagebits = 64,
166+
.endianness = IIO_LE,
167+
},
168+
},
169+
};
170+
171+
static int smgr_accel_probe(struct platform_device *pdev)
172+
{
173+
struct iio_dev *iio_dev;
174+
struct smgr_iio_priv *priv;
175+
int ret;
176+
177+
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
178+
if (!iio_dev)
179+
return -ENOMEM;
180+
181+
priv = iio_priv(iio_dev);
182+
priv->sensor = *(struct smgr_sensor **)pdev->dev.platform_data;
183+
priv->sensor->iio_dev = iio_dev;
184+
185+
iio_dev->name = "qcom-smgr-accel";
186+
iio_dev->info = &smgr_accel_iio_info;
187+
iio_dev->channels = smgr_accel_iio_channels;
188+
iio_dev->num_channels = ARRAY_SIZE(smgr_accel_iio_channels);
189+
190+
ret = devm_iio_kfifo_buffer_setup(&pdev->dev, iio_dev,
191+
&smgr_buffer_ops);
192+
if (ret) {
193+
dev_err(&pdev->dev, "Failed to setup buffer: %pe\n",
194+
ERR_PTR(ret));
195+
return ret;
196+
}
197+
198+
ret = devm_iio_device_register(&pdev->dev, iio_dev);
199+
if (ret) {
200+
dev_err(&pdev->dev, "Failed to register IIO device: %pe\n",
201+
ERR_PTR(ret));
202+
return ret;
203+
}
204+
205+
return 0;
206+
}
207+
208+
static void smgr_accel_remove(struct platform_device *pdev)
209+
{
210+
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
211+
struct smgr_iio_priv *priv = iio_priv(iio_dev);
212+
213+
priv->sensor->iio_dev = NULL;
214+
}
215+
216+
static const struct platform_device_id smgr_accel_ids[] = {
217+
{ .name = "qcom-smgr-accel" },
218+
{ /* sentinel */ }
219+
};
220+
MODULE_DEVICE_TABLE(platform, smgr_accel_ids);
221+
222+
static struct platform_driver smgr_accel_driver = {
223+
.probe = smgr_accel_probe,
224+
.remove = smgr_accel_remove,
225+
.driver = {
226+
.name = "smgr_accel",
227+
},
228+
.id_table = smgr_accel_ids,
229+
};
230+
module_platform_driver(smgr_accel_driver);
231+
232+
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
233+
MODULE_DESCRIPTION("Qualcomm Sensor Manager accelerometer driver");
234+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)