1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a9afcaa6SKarol Wrona /*
3a9afcaa6SKarol Wrona * Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.
4a9afcaa6SKarol Wrona */
5a9afcaa6SKarol Wrona
6a9afcaa6SKarol Wrona #include <linux/iio/common/ssp_sensors.h>
7a9afcaa6SKarol Wrona #include <linux/iio/iio.h>
88abd5ba5SJonathan Cameron #include <linux/iio/buffer.h>
9a9afcaa6SKarol Wrona #include <linux/iio/kfifo_buf.h>
10a9afcaa6SKarol Wrona #include <linux/module.h>
11a9afcaa6SKarol Wrona #include <linux/platform_device.h>
12a9afcaa6SKarol Wrona #include <linux/slab.h>
13a9afcaa6SKarol Wrona #include "../common/ssp_sensors/ssp_iio_sensor.h"
14a9afcaa6SKarol Wrona
15a9afcaa6SKarol Wrona #define SSP_CHANNEL_COUNT 3
16a9afcaa6SKarol Wrona
17a9afcaa6SKarol Wrona #define SSP_GYROSCOPE_NAME "ssp-gyroscope"
18a9afcaa6SKarol Wrona static const char ssp_gyro_name[] = SSP_GYROSCOPE_NAME;
19a9afcaa6SKarol Wrona
20a9afcaa6SKarol Wrona enum ssp_gyro_3d_channel {
21a9afcaa6SKarol Wrona SSP_CHANNEL_SCAN_INDEX_X,
22a9afcaa6SKarol Wrona SSP_CHANNEL_SCAN_INDEX_Y,
23a9afcaa6SKarol Wrona SSP_CHANNEL_SCAN_INDEX_Z,
24a9afcaa6SKarol Wrona SSP_CHANNEL_SCAN_INDEX_TIME,
25a9afcaa6SKarol Wrona };
26a9afcaa6SKarol Wrona
ssp_gyro_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)27a9afcaa6SKarol Wrona static int ssp_gyro_read_raw(struct iio_dev *indio_dev,
28a9afcaa6SKarol Wrona struct iio_chan_spec const *chan, int *val,
29a9afcaa6SKarol Wrona int *val2, long mask)
30a9afcaa6SKarol Wrona {
31a9afcaa6SKarol Wrona u32 t;
32a9afcaa6SKarol Wrona struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
33a9afcaa6SKarol Wrona
34a9afcaa6SKarol Wrona switch (mask) {
35a9afcaa6SKarol Wrona case IIO_CHAN_INFO_SAMP_FREQ:
36a9afcaa6SKarol Wrona t = ssp_get_sensor_delay(data, SSP_GYROSCOPE_SENSOR);
37a9afcaa6SKarol Wrona ssp_convert_to_freq(t, val, val2);
38a9afcaa6SKarol Wrona return IIO_VAL_INT_PLUS_MICRO;
39a9afcaa6SKarol Wrona default:
40a9afcaa6SKarol Wrona break;
41a9afcaa6SKarol Wrona }
42a9afcaa6SKarol Wrona
43a9afcaa6SKarol Wrona return -EINVAL;
44a9afcaa6SKarol Wrona }
45a9afcaa6SKarol Wrona
ssp_gyro_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)46a9afcaa6SKarol Wrona static int ssp_gyro_write_raw(struct iio_dev *indio_dev,
47a9afcaa6SKarol Wrona struct iio_chan_spec const *chan, int val,
48a9afcaa6SKarol Wrona int val2, long mask)
49a9afcaa6SKarol Wrona {
50a9afcaa6SKarol Wrona int ret;
51a9afcaa6SKarol Wrona struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
52a9afcaa6SKarol Wrona
53a9afcaa6SKarol Wrona switch (mask) {
54a9afcaa6SKarol Wrona case IIO_CHAN_INFO_SAMP_FREQ:
55a9afcaa6SKarol Wrona ret = ssp_convert_to_time(val, val2);
56a9afcaa6SKarol Wrona ret = ssp_change_delay(data, SSP_GYROSCOPE_SENSOR, ret);
57a9afcaa6SKarol Wrona if (ret < 0)
58a9afcaa6SKarol Wrona dev_err(&indio_dev->dev, "gyro sensor enable fail\n");
59a9afcaa6SKarol Wrona
60a9afcaa6SKarol Wrona return ret;
61a9afcaa6SKarol Wrona default:
62a9afcaa6SKarol Wrona break;
63a9afcaa6SKarol Wrona }
64a9afcaa6SKarol Wrona
65a9afcaa6SKarol Wrona return -EINVAL;
66a9afcaa6SKarol Wrona }
67a9afcaa6SKarol Wrona
68becf05e7SJulia Lawall static const struct iio_info ssp_gyro_iio_info = {
69a9afcaa6SKarol Wrona .read_raw = &ssp_gyro_read_raw,
70a9afcaa6SKarol Wrona .write_raw = &ssp_gyro_write_raw,
71a9afcaa6SKarol Wrona };
72a9afcaa6SKarol Wrona
73a9afcaa6SKarol Wrona static const unsigned long ssp_gyro_scan_mask[] = { 0x07, 0, };
74a9afcaa6SKarol Wrona
75a9afcaa6SKarol Wrona static const struct iio_chan_spec ssp_gyro_channels[] = {
76a9afcaa6SKarol Wrona SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
77a9afcaa6SKarol Wrona SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
78a9afcaa6SKarol Wrona SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
79a9afcaa6SKarol Wrona SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
80a9afcaa6SKarol Wrona };
81a9afcaa6SKarol Wrona
ssp_process_gyro_data(struct iio_dev * indio_dev,void * buf,int64_t timestamp)82a9afcaa6SKarol Wrona static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf,
83a9afcaa6SKarol Wrona int64_t timestamp)
84a9afcaa6SKarol Wrona {
85a9afcaa6SKarol Wrona return ssp_common_process_data(indio_dev, buf, SSP_GYROSCOPE_SIZE,
86a9afcaa6SKarol Wrona timestamp);
87a9afcaa6SKarol Wrona }
88a9afcaa6SKarol Wrona
89a9afcaa6SKarol Wrona static const struct iio_buffer_setup_ops ssp_gyro_buffer_ops = {
90a9afcaa6SKarol Wrona .postenable = &ssp_common_buffer_postenable,
91a9afcaa6SKarol Wrona .postdisable = &ssp_common_buffer_postdisable,
92a9afcaa6SKarol Wrona };
93a9afcaa6SKarol Wrona
ssp_gyro_probe(struct platform_device * pdev)94a9afcaa6SKarol Wrona static int ssp_gyro_probe(struct platform_device *pdev)
95a9afcaa6SKarol Wrona {
96a9afcaa6SKarol Wrona int ret;
97a9afcaa6SKarol Wrona struct iio_dev *indio_dev;
98a9afcaa6SKarol Wrona struct ssp_sensor_data *spd;
99a9afcaa6SKarol Wrona
100a9afcaa6SKarol Wrona indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
101a9afcaa6SKarol Wrona if (!indio_dev)
102a9afcaa6SKarol Wrona return -ENOMEM;
103a9afcaa6SKarol Wrona
104a9afcaa6SKarol Wrona spd = iio_priv(indio_dev);
105a9afcaa6SKarol Wrona
106a9afcaa6SKarol Wrona spd->process_data = ssp_process_gyro_data;
107a9afcaa6SKarol Wrona spd->type = SSP_GYROSCOPE_SENSOR;
108a9afcaa6SKarol Wrona
109a9afcaa6SKarol Wrona indio_dev->name = ssp_gyro_name;
110a9afcaa6SKarol Wrona indio_dev->info = &ssp_gyro_iio_info;
111a9afcaa6SKarol Wrona indio_dev->channels = ssp_gyro_channels;
112a9afcaa6SKarol Wrona indio_dev->num_channels = ARRAY_SIZE(ssp_gyro_channels);
113a9afcaa6SKarol Wrona indio_dev->available_scan_masks = ssp_gyro_scan_mask;
114a9afcaa6SKarol Wrona
11517395ce2SAlexandru Ardelean ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev,
11617395ce2SAlexandru Ardelean &ssp_gyro_buffer_ops);
11717395ce2SAlexandru Ardelean if (ret)
11817395ce2SAlexandru Ardelean return ret;
119a9afcaa6SKarol Wrona
120a9afcaa6SKarol Wrona platform_set_drvdata(pdev, indio_dev);
121a9afcaa6SKarol Wrona
122752d01d9SWei Yongjun ret = devm_iio_device_register(&pdev->dev, indio_dev);
123a9afcaa6SKarol Wrona if (ret < 0)
124a9afcaa6SKarol Wrona return ret;
125a9afcaa6SKarol Wrona
126a9afcaa6SKarol Wrona /* ssp registering should be done after all iio setup */
127a9afcaa6SKarol Wrona ssp_register_consumer(indio_dev, SSP_GYROSCOPE_SENSOR);
128a9afcaa6SKarol Wrona
129a9afcaa6SKarol Wrona return 0;
130a9afcaa6SKarol Wrona }
131a9afcaa6SKarol Wrona
132a9afcaa6SKarol Wrona static struct platform_driver ssp_gyro_driver = {
133a9afcaa6SKarol Wrona .driver = {
134a9afcaa6SKarol Wrona .name = SSP_GYROSCOPE_NAME,
135a9afcaa6SKarol Wrona },
136a9afcaa6SKarol Wrona .probe = ssp_gyro_probe,
137a9afcaa6SKarol Wrona };
138a9afcaa6SKarol Wrona
139a9afcaa6SKarol Wrona module_platform_driver(ssp_gyro_driver);
140a9afcaa6SKarol Wrona
141a9afcaa6SKarol Wrona MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
142a9afcaa6SKarol Wrona MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver");
143a9afcaa6SKarol Wrona MODULE_LICENSE("GPL");
144*0a1b56b7SJonathan Cameron MODULE_IMPORT_NS(IIO_SSP_SENSORS);
145