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