xref: /openbmc/linux/drivers/iio/gyro/ssp_gyro_sensor.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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