aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorKarol Wrona <k.wrona@samsung.com>2015-01-28 09:05:50 -0500
committerJonathan Cameron <jic23@kernel.org>2015-01-29 13:49:05 -0500
commit50dd64d57eee8aed1a86e875ce77d078e44fad00 (patch)
tree9ff907c4488b35999f28c8d1fa55fc1c46e8e628 /drivers/iio
parent1664f6a5b0c85a006126c398988d06a0059a50a4 (diff)
iio: common: ssp_sensors: Add sensorhub driver
Sensorhub is MCU dedicated to collect data and manage several sensors. Sensorhub is a spi device which provides a layer for IIO devices. It provides some data parsing and common mechanism for sensorhub sensors. Adds common sensorhub library for sensorhub driver and iio drivers which uses sensorhub MCU to communicate with sensors. Signed-off-by: Karol Wrona <k.wrona@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/ssp_sensors/Kconfig16
-rw-r--r--drivers/iio/common/ssp_sensors/Makefile6
-rw-r--r--drivers/iio/common/ssp_sensors/ssp.h257
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_dev.c712
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_spi.c608
7 files changed, 1601 insertions, 0 deletions
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 0b6e97d18fa0..790f106d719c 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,4 +3,5 @@
3# 3#
4 4
5source "drivers/iio/common/hid-sensors/Kconfig" 5source "drivers/iio/common/hid-sensors/Kconfig"
6source "drivers/iio/common/ssp_sensors/Kconfig"
6source "drivers/iio/common/st_sensors/Kconfig" 7source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index 3112df0060e9..b1e4d9c9591c 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,4 +8,5 @@
8 8
9# When adding new entries keep the list in alphabetical order 9# When adding new entries keep the list in alphabetical order
10obj-y += hid-sensors/ 10obj-y += hid-sensors/
11obj-y += ssp_sensors/
11obj-y += st_sensors/ 12obj-y += st_sensors/
diff --git a/drivers/iio/common/ssp_sensors/Kconfig b/drivers/iio/common/ssp_sensors/Kconfig
new file mode 100644
index 000000000000..759b975e2b40
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Kconfig
@@ -0,0 +1,16 @@
1#
2# SSP sensor drivers and commons configuration
3#
4menu "SSP Sensor Common"
5
6config IIO_SSP_SENSORHUB
7 tristate "Samsung Sensorhub driver"
8 depends on SPI
9 select MFD_CORE
10 help
11 SSP driver for sensorhub.
12 If you say yes here you get ssp support for sensorhub.
13 To compile this driver as a module, choose M here: the
14 module will be called sensorhub.
15
16endmenu
diff --git a/drivers/iio/common/ssp_sensors/Makefile b/drivers/iio/common/ssp_sensors/Makefile
new file mode 100644
index 000000000000..07d3d6a6763b
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for SSP sensor drivers and commons.
3#
4
5sensorhub-objs := ssp_dev.o ssp_spi.o
6obj-$(CONFIG_IIO_SSP_SENSORHUB) += sensorhub.o
diff --git a/drivers/iio/common/ssp_sensors/ssp.h b/drivers/iio/common/ssp_sensors/ssp.h
new file mode 100644
index 000000000000..b910e91d7c0d
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp.h
@@ -0,0 +1,257 @@
1/*
2 * Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#ifndef __SSP_SENSORHUB_H__
17#define __SSP_SENSORHUB_H__
18
19#include <linux/delay.h>
20#include <linux/gpio.h>
21#include <linux/iio/common/ssp_sensors.h>
22#include <linux/iio/iio.h>
23#include <linux/spi/spi.h>
24
25#define SSP_DEVICE_ID 0x55
26
27#ifdef SSP_DBG
28#define ssp_dbg(format, ...) pr_info("[SSP] "format, ##__VA_ARGS__)
29#else
30#define ssp_dbg(format, ...)
31#endif
32
33#define SSP_SW_RESET_TIME 3000
34/* Sensor polling in ms */
35#define SSP_DEFAULT_POLLING_DELAY 200
36#define SSP_DEFAULT_RETRIES 3
37#define SSP_DATA_PACKET_SIZE 960
38#define SSP_HEADER_BUFFER_SIZE 4
39
40enum {
41 SSP_KERNEL_BINARY = 0,
42 SSP_KERNEL_CRASHED_BINARY,
43};
44
45enum {
46 SSP_INITIALIZATION_STATE = 0,
47 SSP_NO_SENSOR_STATE,
48 SSP_ADD_SENSOR_STATE,
49 SSP_RUNNING_SENSOR_STATE,
50};
51
52/* Firmware download STATE */
53enum {
54 SSP_FW_DL_STATE_FAIL = -1,
55 SSP_FW_DL_STATE_NONE = 0,
56 SSP_FW_DL_STATE_NEED_TO_SCHEDULE,
57 SSP_FW_DL_STATE_SCHEDULED,
58 SSP_FW_DL_STATE_DOWNLOADING,
59 SSP_FW_DL_STATE_SYNC,
60 SSP_FW_DL_STATE_DONE,
61};
62
63#define SSP_INVALID_REVISION 99999
64#define SSP_INVALID_REVISION2 0xffffff
65
66/* AP -> SSP Instruction */
67#define SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD 0xa1
68#define SSP_MSG2SSP_INST_BYPASS_SENSOR_RM 0xa2
69#define SSP_MSG2SSP_INST_REMOVE_ALL 0xa3
70#define SSP_MSG2SSP_INST_CHANGE_DELAY 0xa4
71#define SSP_MSG2SSP_INST_LIBRARY_ADD 0xb1
72#define SSP_MSG2SSP_INST_LIBRARY_REMOVE 0xb2
73#define SSP_MSG2SSP_INST_LIB_NOTI 0xb4
74#define SSP_MSG2SSP_INST_LIB_DATA 0xc1
75
76#define SSP_MSG2SSP_AP_MCU_SET_GYRO_CAL 0xcd
77#define SSP_MSG2SSP_AP_MCU_SET_ACCEL_CAL 0xce
78#define SSP_MSG2SSP_AP_STATUS_SHUTDOWN 0xd0
79#define SSP_MSG2SSP_AP_STATUS_WAKEUP 0xd1
80#define SSP_MSG2SSP_AP_STATUS_SLEEP 0xd2
81#define SSP_MSG2SSP_AP_STATUS_RESUME 0xd3
82#define SSP_MSG2SSP_AP_STATUS_SUSPEND 0xd4
83#define SSP_MSG2SSP_AP_STATUS_RESET 0xd5
84#define SSP_MSG2SSP_AP_STATUS_POW_CONNECTED 0xd6
85#define SSP_MSG2SSP_AP_STATUS_POW_DISCONNECTED 0xd7
86#define SSP_MSG2SSP_AP_TEMPHUMIDITY_CAL_DONE 0xda
87#define SSP_MSG2SSP_AP_MCU_SET_DUMPMODE 0xdb
88#define SSP_MSG2SSP_AP_MCU_DUMP_CHECK 0xdc
89#define SSP_MSG2SSP_AP_MCU_BATCH_FLUSH 0xdd
90#define SSP_MSG2SSP_AP_MCU_BATCH_COUNT 0xdf
91
92#define SSP_MSG2SSP_AP_WHOAMI 0x0f
93#define SSP_MSG2SSP_AP_FIRMWARE_REV 0xf0
94#define SSP_MSG2SSP_AP_SENSOR_FORMATION 0xf1
95#define SSP_MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xf2
96#define SSP_MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xf3
97#define SSP_MSG2SSP_AP_SENSOR_SCANNING 0xf4
98#define SSP_MSG2SSP_AP_SET_MAGNETIC_HWOFFSET 0xf5
99#define SSP_MSG2SSP_AP_GET_MAGNETIC_HWOFFSET 0xf6
100#define SSP_MSG2SSP_AP_SENSOR_GESTURE_CURRENT 0xf7
101#define SSP_MSG2SSP_AP_GET_THERM 0xf8
102#define SSP_MSG2SSP_AP_GET_BIG_DATA 0xf9
103#define SSP_MSG2SSP_AP_SET_BIG_DATA 0xfa
104#define SSP_MSG2SSP_AP_START_BIG_DATA 0xfb
105#define SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX 0xfd
106#define SSP_MSG2SSP_AP_SENSOR_TILT 0xea
107#define SSP_MSG2SSP_AP_MCU_SET_TIME 0xfe
108#define SSP_MSG2SSP_AP_MCU_GET_TIME 0xff
109
110#define SSP_MSG2SSP_AP_FUSEROM 0x01
111
112/* voice data */
113#define SSP_TYPE_WAKE_UP_VOICE_SERVICE 0x01
114#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_AM 0x01
115#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_GRAMMER 0x02
116
117/* Factory Test */
118#define SSP_ACCELEROMETER_FACTORY 0x80
119#define SSP_GYROSCOPE_FACTORY 0x81
120#define SSP_GEOMAGNETIC_FACTORY 0x82
121#define SSP_PRESSURE_FACTORY 0x85
122#define SSP_GESTURE_FACTORY 0x86
123#define SSP_TEMPHUMIDITY_CRC_FACTORY 0x88
124#define SSP_GYROSCOPE_TEMP_FACTORY 0x8a
125#define SSP_GYROSCOPE_DPS_FACTORY 0x8b
126#define SSP_MCU_FACTORY 0x8c
127#define SSP_MCU_SLEEP_FACTORY 0x8d
128
129/* SSP -> AP ACK about write CMD */
130#define SSP_MSG_ACK 0x80 /* ACK from SSP to AP */
131#define SSP_MSG_NAK 0x70 /* NAK from SSP to AP */
132
133struct ssp_sensorhub_info {
134 char *fw_name;
135 char *fw_crashed_name;
136 unsigned int fw_rev;
137 const u8 * const mag_table;
138 const unsigned int mag_length;
139};
140
141/* ssp_msg options bit */
142#define SSP_RW 0
143#define SSP_INDEX 3
144
145#define SSP_AP2HUB_READ 0
146#define SSP_AP2HUB_WRITE 1
147#define SSP_HUB2AP_WRITE 2
148#define SSP_AP2HUB_READY 3
149#define SSP_AP2HUB_RETURN 4
150
151/**
152 * struct ssp_data - ssp platformdata structure
153 * @spi: spi device
154 * @sensorhub_info: info about sensorhub board specific features
155 * @wdt_timer: watchdog timer
156 * @work_wdt: watchdog work
157 * @work_firmware: firmware upgrade work queue
158 * @work_refresh: refresh work queue for reset request from MCU
159 * @shut_down: shut down flag
160 * @mcu_dump_mode: mcu dump mode for debug
161 * @time_syncing: time syncing indication flag
162 * @timestamp: previous time in ns calculated for time syncing
163 * @check_status: status table for each sensor
164 * @com_fail_cnt: communication fail count
165 * @reset_cnt: reset count
166 * @timeout_cnt: timeout count
167 * @available_sensors: available sensors seen by sensorhub (bit array)
168 * @cur_firm_rev: cached current firmware revision
169 * @last_resume_state: last AP resume/suspend state used to handle the PM
170 * state of ssp
171 * @last_ap_state: (obsolete) sleep notification for MCU
172 * @sensor_enable: sensor enable mask
173 * @delay_buf: data acquisition intervals table
174 * @batch_latency_buf: yet unknown but existing in communication protocol
175 * @batch_opt_buf: yet unknown but existing in communication protocol
176 * @accel_position: yet unknown but existing in communication protocol
177 * @mag_position: yet unknown but existing in communication protocol
178 * @fw_dl_state: firmware download state
179 * @comm_lock: lock protecting the handshake
180 * @pending_lock: lock protecting pending list and completion
181 * @mcu_reset_gpio: mcu reset line
182 * @ap_mcu_gpio: ap to mcu gpio line
183 * @mcu_ap_gpio: mcu to ap gpio line
184 * @pending_list: pending list for messages queued to be sent/read
185 * @sensor_devs: registered IIO devices table
186 * @enable_refcount: enable reference count for wdt (watchdog timer)
187 * @header_buffer: cache aligned buffer for packet header
188 */
189struct ssp_data {
190 struct spi_device *spi;
191 struct ssp_sensorhub_info *sensorhub_info;
192 struct timer_list wdt_timer;
193 struct work_struct work_wdt;
194 struct delayed_work work_refresh;
195
196 bool shut_down;
197 bool mcu_dump_mode;
198 bool time_syncing;
199 int64_t timestamp;
200
201 int check_status[SSP_SENSOR_MAX];
202
203 unsigned int com_fail_cnt;
204 unsigned int reset_cnt;
205 unsigned int timeout_cnt;
206
207 unsigned int available_sensors;
208 unsigned int cur_firm_rev;
209
210 char last_resume_state;
211 char last_ap_state;
212
213 unsigned int sensor_enable;
214 u32 delay_buf[SSP_SENSOR_MAX];
215 s32 batch_latency_buf[SSP_SENSOR_MAX];
216 s8 batch_opt_buf[SSP_SENSOR_MAX];
217
218 int accel_position;
219 int mag_position;
220 int fw_dl_state;
221
222 struct mutex comm_lock;
223 struct mutex pending_lock;
224
225 int mcu_reset_gpio;
226 int ap_mcu_gpio;
227 int mcu_ap_gpio;
228
229 struct list_head pending_list;
230
231 struct iio_dev *sensor_devs[SSP_SENSOR_MAX];
232 atomic_t enable_refcount;
233
234 __le16 header_buffer[SSP_HEADER_BUFFER_SIZE / sizeof(__le16)]
235 ____cacheline_aligned;
236};
237
238void ssp_clean_pending_list(struct ssp_data *data);
239
240int ssp_command(struct ssp_data *data, char command, int arg);
241
242int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
243 u8 *send_buf, u8 length);
244
245int ssp_irq_msg(struct ssp_data *data);
246
247int ssp_get_chipid(struct ssp_data *data);
248
249int ssp_set_magnetic_matrix(struct ssp_data *data);
250
251unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data);
252
253unsigned int ssp_get_firmware_rev(struct ssp_data *data);
254
255int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay);
256
257#endif /* __SSP_SENSORHUB_H__ */
diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c
new file mode 100644
index 000000000000..52d70435f5a1
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_dev.c
@@ -0,0 +1,712 @@
1/*
2 * Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/iio/iio.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/mfd/core.h>
20#include <linux/module.h>
21#include <linux/of.h>
22#include <linux/of_gpio.h>
23#include <linux/of_platform.h>
24#include "ssp.h"
25
26#define SSP_WDT_TIME 10000
27#define SSP_LIMIT_RESET_CNT 20
28#define SSP_LIMIT_TIMEOUT_CNT 3
29
30/* It is possible that it is max clk rate for version 1.0 of bootcode */
31#define SSP_BOOT_SPI_HZ 400000
32
33/*
34 * These fields can look enigmatic but this structure is used mainly to flat
35 * some values and depends on command type.
36 */
37struct ssp_instruction {
38 __le32 a;
39 __le32 b;
40 u8 c;
41} __attribute__((__packed__));
42
43static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,
44 208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,
45 243, 13, 45, 250};
46
47static const struct ssp_sensorhub_info ssp_rinato_info = {
48 .fw_name = "ssp_B2.fw",
49 .fw_crashed_name = "ssp_crashed.fw",
50 .fw_rev = 14052300,
51 .mag_table = ssp_magnitude_table,
52 .mag_length = ARRAY_SIZE(ssp_magnitude_table),
53};
54
55static const struct ssp_sensorhub_info ssp_thermostat_info = {
56 .fw_name = "thermostat_B2.fw",
57 .fw_crashed_name = "ssp_crashed.fw",
58 .fw_rev = 14080600,
59 .mag_table = ssp_magnitude_table,
60 .mag_length = ARRAY_SIZE(ssp_magnitude_table),
61};
62
63static const struct mfd_cell sensorhub_sensor_devs[] = {
64 {
65 .name = "ssp-accelerometer",
66 },
67 {
68 .name = "ssp-gyroscope",
69 },
70};
71
72static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
73{
74 gpio_set_value(data->mcu_reset_gpio, 0);
75 usleep_range(1000, 1200);
76 gpio_set_value(data->mcu_reset_gpio, 1);
77 msleep(50);
78}
79
80static void ssp_sync_available_sensors(struct ssp_data *data)
81{
82 int i, ret;
83
84 for (i = 0; i < SSP_SENSOR_MAX; ++i) {
85 if (data->available_sensors & BIT(i)) {
86 ret = ssp_enable_sensor(data, i, data->delay_buf[i]);
87 if (ret < 0) {
88 dev_err(&data->spi->dev,
89 "Sync sensor nr: %d fail\n", i);
90 continue;
91 }
92 }
93 }
94
95 ret = ssp_command(data, SSP_MSG2SSP_AP_MCU_SET_DUMPMODE,
96 data->mcu_dump_mode);
97 if (ret < 0)
98 dev_err(&data->spi->dev,
99 "SSP_MSG2SSP_AP_MCU_SET_DUMPMODE failed\n");
100}
101
102static void ssp_enable_mcu(struct ssp_data *data, bool enable)
103{
104 dev_info(&data->spi->dev, "current shutdown = %d, old = %d\n", enable,
105 data->shut_down);
106
107 if (enable && data->shut_down) {
108 data->shut_down = false;
109 enable_irq(data->spi->irq);
110 enable_irq_wake(data->spi->irq);
111 } else if (!enable && !data->shut_down) {
112 data->shut_down = true;
113 disable_irq(data->spi->irq);
114 disable_irq_wake(data->spi->irq);
115 } else {
116 dev_warn(&data->spi->dev, "current shutdown = %d, old = %d\n",
117 enable, data->shut_down);
118 }
119}
120
121/*
122 * This function is the first one which communicates with the mcu so it is
123 * possible that the first attempt will fail
124 */
125static int ssp_check_fwbl(struct ssp_data *data)
126{
127 int retries = 0;
128
129 while (retries++ < 5) {
130 data->cur_firm_rev = ssp_get_firmware_rev(data);
131 if (data->cur_firm_rev == SSP_INVALID_REVISION ||
132 data->cur_firm_rev == SSP_INVALID_REVISION2) {
133 dev_warn(&data->spi->dev,
134 "Invalid revision, trying %d time\n", retries);
135 } else {
136 break;
137 }
138 }
139
140 if (data->cur_firm_rev == SSP_INVALID_REVISION ||
141 data->cur_firm_rev == SSP_INVALID_REVISION2) {
142 dev_err(&data->spi->dev, "SSP_INVALID_REVISION\n");
143 return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
144 }
145
146 dev_info(&data->spi->dev,
147 "MCU Firm Rev : Old = %8u, New = %8u\n",
148 data->cur_firm_rev,
149 data->sensorhub_info->fw_rev);
150
151 if (data->cur_firm_rev != data->sensorhub_info->fw_rev)
152 return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
153
154 return SSP_FW_DL_STATE_NONE;
155}
156
157static void ssp_reset_mcu(struct ssp_data *data)
158{
159 ssp_enable_mcu(data, false);
160 ssp_clean_pending_list(data);
161 ssp_toggle_mcu_reset_gpio(data);
162 ssp_enable_mcu(data, true);
163}
164
165static void ssp_wdt_work_func(struct work_struct *work)
166{
167 struct ssp_data *data = container_of(work, struct ssp_data, work_wdt);
168
169 dev_err(&data->spi->dev, "%s - Sensor state: 0x%x, RC: %u, CC: %u\n",
170 __func__, data->available_sensors, data->reset_cnt,
171 data->com_fail_cnt);
172
173 ssp_reset_mcu(data);
174 data->com_fail_cnt = 0;
175 data->timeout_cnt = 0;
176}
177
178static void ssp_wdt_timer_func(unsigned long ptr)
179{
180 struct ssp_data *data = (struct ssp_data *)ptr;
181
182 switch (data->fw_dl_state) {
183 case SSP_FW_DL_STATE_FAIL:
184 case SSP_FW_DL_STATE_DOWNLOADING:
185 case SSP_FW_DL_STATE_SYNC:
186 goto _mod;
187 }
188
189 if (data->timeout_cnt > SSP_LIMIT_TIMEOUT_CNT ||
190 data->com_fail_cnt > SSP_LIMIT_RESET_CNT)
191 queue_work(system_power_efficient_wq, &data->work_wdt);
192_mod:
193 mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
194}
195
196static void ssp_enable_wdt_timer(struct ssp_data *data)
197{
198 mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
199}
200
201static void ssp_disable_wdt_timer(struct ssp_data *data)
202{
203 del_timer_sync(&data->wdt_timer);
204 cancel_work_sync(&data->work_wdt);
205}
206
207/**
208 * ssp_get_sensor_delay() - gets sensor data acquisition period
209 * @data: sensorhub structure
210 * @type: SSP sensor type
211 *
212 * Returns acquisition period in ms
213 */
214u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)
215{
216 return data->delay_buf[type];
217}
218EXPORT_SYMBOL(ssp_get_sensor_delay);
219
220/**
221 * ssp_enable_sensor() - enables data acquisition for sensor
222 * @data: sensorhub structure
223 * @type: SSP sensor type
224 * @delay: delay in ms
225 *
226 * Returns 0 or negative value in case of error
227 */
228int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
229 u32 delay)
230{
231 int ret;
232 struct ssp_instruction to_send;
233
234 to_send.a = cpu_to_le32(delay);
235 to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
236 to_send.c = data->batch_opt_buf[type];
237
238 switch (data->check_status[type]) {
239 case SSP_INITIALIZATION_STATE:
240 /* do calibration step, now just enable */
241 case SSP_ADD_SENSOR_STATE:
242 ret = ssp_send_instruction(data,
243 SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD,
244 type,
245 (u8 *)&to_send, sizeof(to_send));
246 if (ret < 0) {
247 dev_err(&data->spi->dev, "Enabling sensor failed\n");
248 data->check_status[type] = SSP_NO_SENSOR_STATE;
249 goto derror;
250 }
251
252 data->sensor_enable |= BIT(type);
253 data->check_status[type] = SSP_RUNNING_SENSOR_STATE;
254 break;
255 case SSP_RUNNING_SENSOR_STATE:
256 ret = ssp_send_instruction(data,
257 SSP_MSG2SSP_INST_CHANGE_DELAY, type,
258 (u8 *)&to_send, sizeof(to_send));
259 if (ret < 0) {
260 dev_err(&data->spi->dev,
261 "Changing sensor delay failed\n");
262 goto derror;
263 }
264 break;
265 default:
266 data->check_status[type] = SSP_ADD_SENSOR_STATE;
267 break;
268 }
269
270 data->delay_buf[type] = delay;
271
272 if (atomic_inc_return(&data->enable_refcount) == 1)
273 ssp_enable_wdt_timer(data);
274
275 return 0;
276
277derror:
278 return ret;
279}
280EXPORT_SYMBOL(ssp_enable_sensor);
281
282/**
283 * ssp_change_delay() - changes data acquisition for sensor
284 * @data: sensorhub structure
285 * @type: SSP sensor type
286 * @delay: delay in ms
287 *
288 * Returns 0 or negative value in case of error
289 */
290int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
291 u32 delay)
292{
293 int ret;
294 struct ssp_instruction to_send;
295
296 to_send.a = cpu_to_le32(delay);
297 to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
298 to_send.c = data->batch_opt_buf[type];
299
300 ret = ssp_send_instruction(data, SSP_MSG2SSP_INST_CHANGE_DELAY, type,
301 (u8 *)&to_send, sizeof(to_send));
302 if (ret < 0) {
303 dev_err(&data->spi->dev, "Changing sensor delay failed\n");
304 return ret;
305 }
306
307 data->delay_buf[type] = delay;
308
309 return 0;
310}
311EXPORT_SYMBOL(ssp_change_delay);
312
313/**
314 * ssp_disable_sensor() - disables sensor
315 *
316 * @data: sensorhub structure
317 * @type: SSP sensor type
318 *
319 * Returns 0 or negative value in case of error
320 */
321int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)
322{
323 int ret;
324 __le32 command;
325
326 if (data->sensor_enable & BIT(type)) {
327 command = cpu_to_le32(data->delay_buf[type]);
328
329 ret = ssp_send_instruction(data,
330 SSP_MSG2SSP_INST_BYPASS_SENSOR_RM,
331 type, (u8 *)&command,
332 sizeof(command));
333 if (ret < 0) {
334 dev_err(&data->spi->dev, "Remove sensor fail\n");
335 return ret;
336 }
337
338 data->sensor_enable &= ~BIT(type);
339 }
340
341 data->check_status[type] = SSP_ADD_SENSOR_STATE;
342
343 if (atomic_dec_and_test(&data->enable_refcount))
344 ssp_disable_wdt_timer(data);
345
346 return 0;
347}
348EXPORT_SYMBOL(ssp_disable_sensor);
349
350static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)
351{
352 struct ssp_data *data = dev_id;
353
354 /*
355 * This wrapper is done to preserve error path for ssp_irq_msg, also
356 * it is defined in different file.
357 */
358 ssp_irq_msg(data);
359
360 return IRQ_HANDLED;
361}
362
363static int ssp_initialize_mcu(struct ssp_data *data)
364{
365 int ret;
366
367 ssp_clean_pending_list(data);
368
369 ret = ssp_get_chipid(data);
370 if (ret != SSP_DEVICE_ID) {
371 dev_err(&data->spi->dev, "%s - MCU %s ret = %d\n", __func__,
372 ret < 0 ? "is not working" : "identification failed",
373 ret);
374 return ret < 0 ? ret : -ENODEV;
375 }
376
377 dev_info(&data->spi->dev, "MCU device ID = %d\n", ret);
378
379 /*
380 * needs clarification, for now do not want to export all transfer
381 * methods to sensors' drivers
382 */
383 ret = ssp_set_magnetic_matrix(data);
384 if (ret < 0) {
385 dev_err(&data->spi->dev,
386 "%s - ssp_set_magnetic_matrix failed\n", __func__);
387 return ret;
388 }
389
390 data->available_sensors = ssp_get_sensor_scanning_info(data);
391 if (data->available_sensors == 0) {
392 dev_err(&data->spi->dev,
393 "%s - ssp_get_sensor_scanning_info failed\n", __func__);
394 return -EIO;
395 }
396
397 data->cur_firm_rev = ssp_get_firmware_rev(data);
398 dev_info(&data->spi->dev, "MCU Firm Rev : New = %8u\n",
399 data->cur_firm_rev);
400
401 return ssp_command(data, SSP_MSG2SSP_AP_MCU_DUMP_CHECK, 0);
402}
403
404/*
405 * sensorhub can request its reinitialization as some brutal and rare error
406 * handling. It can be requested from the MCU.
407 */
408static void ssp_refresh_task(struct work_struct *work)
409{
410 struct ssp_data *data = container_of((struct delayed_work *)work,
411 struct ssp_data, work_refresh);
412
413 dev_info(&data->spi->dev, "refreshing\n");
414
415 data->reset_cnt++;
416
417 if (ssp_initialize_mcu(data) >= 0) {
418 ssp_sync_available_sensors(data);
419 if (data->last_ap_state != 0)
420 ssp_command(data, data->last_ap_state, 0);
421
422 if (data->last_resume_state != 0)
423 ssp_command(data, data->last_resume_state, 0);
424
425 data->timeout_cnt = 0;
426 data->com_fail_cnt = 0;
427 }
428}
429
430int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
431{
432 cancel_delayed_work_sync(&data->work_refresh);
433
434 return queue_delayed_work(system_power_efficient_wq,
435 &data->work_refresh,
436 msecs_to_jiffies(delay));
437}
438
439#ifdef CONFIG_OF
440static struct of_device_id ssp_of_match[] = {
441 {
442 .compatible = "samsung,sensorhub-rinato",
443 .data = &ssp_rinato_info,
444 }, {
445 .compatible = "samsung,sensorhub-thermostat",
446 .data = &ssp_thermostat_info,
447 },
448 {},
449};
450MODULE_DEVICE_TABLE(of, ssp_of_match);
451
452static struct ssp_data *ssp_parse_dt(struct device *dev)
453{
454 int ret;
455 struct ssp_data *data;
456 struct device_node *node = dev->of_node;
457 const struct of_device_id *match;
458
459 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
460 if (!data)
461 return NULL;
462
463 data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
464 if (data->mcu_ap_gpio < 0)
465 goto err_free_pd;
466
467 data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
468 if (data->ap_mcu_gpio < 0)
469 goto err_free_pd;
470
471 data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
472 if (data->mcu_reset_gpio < 0)
473 goto err_free_pd;
474
475 ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
476 "ap-mcu-gpios");
477 if (ret)
478 goto err_free_pd;
479
480 ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
481 GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
482 if (ret)
483 goto err_ap_mcu;
484
485 match = of_match_node(ssp_of_match, node);
486 if (!match)
487 goto err_mcu_reset_gpio;
488
489 data->sensorhub_info = (struct ssp_sensorhub_info *)match->data;
490
491 dev_set_drvdata(dev, data);
492
493 return data;
494
495err_mcu_reset_gpio:
496 devm_gpio_free(dev, data->mcu_reset_gpio);
497err_ap_mcu:
498 devm_gpio_free(dev, data->ap_mcu_gpio);
499err_free_pd:
500 devm_kfree(dev, data);
501 return NULL;
502}
503#else
504static struct ssp_data *ssp_parse_dt(struct device *pdev)
505{
506 return NULL;
507}
508#endif
509
510/**
511 * ssp_register_consumer() - registers iio consumer in ssp framework
512 *
513 * @indio_dev: consumer iio device
514 * @type: ssp sensor type
515 */
516void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)
517{
518 struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
519
520 data->sensor_devs[type] = indio_dev;
521}
522EXPORT_SYMBOL(ssp_register_consumer);
523
524static int ssp_probe(struct spi_device *spi)
525{
526 int ret, i;
527 struct ssp_data *data;
528
529 data = ssp_parse_dt(&spi->dev);
530 if (!data) {
531 dev_err(&spi->dev, "Failed to find platform data\n");
532 return -ENODEV;
533 }
534
535 ret = mfd_add_devices(&spi->dev, -1, sensorhub_sensor_devs,
536 ARRAY_SIZE(sensorhub_sensor_devs), NULL, 0, NULL);
537 if (ret < 0) {
538 dev_err(&spi->dev, "mfd add devices fail\n");
539 return ret;
540 }
541
542 spi->mode = SPI_MODE_1;
543 ret = spi_setup(spi);
544 if (ret < 0) {
545 dev_err(&spi->dev, "Failed to setup spi\n");
546 return ret;
547 }
548
549 data->fw_dl_state = SSP_FW_DL_STATE_NONE;
550 data->spi = spi;
551 spi_set_drvdata(spi, data);
552
553 mutex_init(&data->comm_lock);
554
555 for (i = 0; i < SSP_SENSOR_MAX; ++i) {
556 data->delay_buf[i] = SSP_DEFAULT_POLLING_DELAY;
557 data->batch_latency_buf[i] = 0;
558 data->batch_opt_buf[i] = 0;
559 data->check_status[i] = SSP_INITIALIZATION_STATE;
560 }
561
562 data->delay_buf[SSP_BIO_HRM_LIB] = 100;
563
564 data->time_syncing = true;
565
566 mutex_init(&data->pending_lock);
567 INIT_LIST_HEAD(&data->pending_list);
568
569 atomic_set(&data->enable_refcount, 0);
570
571 INIT_WORK(&data->work_wdt, ssp_wdt_work_func);
572 INIT_DELAYED_WORK(&data->work_refresh, ssp_refresh_task);
573
574 setup_timer(&data->wdt_timer, ssp_wdt_timer_func, (unsigned long)data);
575
576 ret = request_threaded_irq(data->spi->irq, NULL,
577 ssp_irq_thread_fn,
578 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
579 "SSP_Int", data);
580 if (ret < 0) {
581 dev_err(&spi->dev, "Irq request fail\n");
582 goto err_setup_irq;
583 }
584
585 /* Let's start with enabled one so irq balance could be ok */
586 data->shut_down = false;
587
588 /* just to avoid unbalanced irq set wake up */
589 enable_irq_wake(data->spi->irq);
590
591 data->fw_dl_state = ssp_check_fwbl(data);
592 if (data->fw_dl_state == SSP_FW_DL_STATE_NONE) {
593 ret = ssp_initialize_mcu(data);
594 if (ret < 0) {
595 dev_err(&spi->dev, "Initialize_mcu failed\n");
596 goto err_read_reg;
597 }
598 } else {
599 dev_err(&spi->dev, "Firmware version not supported\n");
600 ret = -EPERM;
601 goto err_read_reg;
602 }
603
604 return 0;
605
606err_read_reg:
607 free_irq(data->spi->irq, data);
608err_setup_irq:
609 mutex_destroy(&data->pending_lock);
610 mutex_destroy(&data->comm_lock);
611
612 dev_err(&spi->dev, "Probe failed!\n");
613
614 return ret;
615}
616
617static int ssp_remove(struct spi_device *spi)
618{
619 struct ssp_data *data = spi_get_drvdata(spi);
620
621 if (ssp_command(data, SSP_MSG2SSP_AP_STATUS_SHUTDOWN, 0) < 0)
622 dev_err(&data->spi->dev,
623 "SSP_MSG2SSP_AP_STATUS_SHUTDOWN failed\n");
624
625 ssp_enable_mcu(data, false);
626 ssp_disable_wdt_timer(data);
627
628 ssp_clean_pending_list(data);
629
630 free_irq(data->spi->irq, data);
631
632 del_timer_sync(&data->wdt_timer);
633 cancel_work_sync(&data->work_wdt);
634
635 mutex_destroy(&data->comm_lock);
636 mutex_destroy(&data->pending_lock);
637
638 mfd_remove_devices(&spi->dev);
639
640 return 0;
641}
642
643static int ssp_suspend(struct device *dev)
644{
645 int ret;
646 struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
647
648 data->last_resume_state = SSP_MSG2SSP_AP_STATUS_SUSPEND;
649
650 if (atomic_read(&data->enable_refcount) > 0)
651 ssp_disable_wdt_timer(data);
652
653 ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_SUSPEND, 0);
654 if (ret < 0) {
655 dev_err(&data->spi->dev,
656 "%s SSP_MSG2SSP_AP_STATUS_SUSPEND failed\n", __func__);
657
658 ssp_enable_wdt_timer(data);
659 return ret;
660 }
661
662 data->time_syncing = false;
663 disable_irq(data->spi->irq);
664
665 return 0;
666}
667
668static int ssp_resume(struct device *dev)
669{
670 int ret;
671 struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
672
673 enable_irq(data->spi->irq);
674
675 if (atomic_read(&data->enable_refcount) > 0)
676 ssp_enable_wdt_timer(data);
677
678 ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_RESUME, 0);
679 if (ret < 0) {
680 dev_err(&data->spi->dev,
681 "%s SSP_MSG2SSP_AP_STATUS_RESUME failed\n", __func__);
682 ssp_disable_wdt_timer(data);
683 return ret;
684 }
685
686 /* timesyncing is set by MCU */
687 data->last_resume_state = SSP_MSG2SSP_AP_STATUS_RESUME;
688
689 return 0;
690}
691
692static const struct dev_pm_ops ssp_pm_ops = {
693 SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
694};
695
696static struct spi_driver ssp_driver = {
697 .probe = ssp_probe,
698 .remove = ssp_remove,
699 .driver = {
700 .pm = &ssp_pm_ops,
701 .bus = &spi_bus_type,
702 .owner = THIS_MODULE,
703 .of_match_table = of_match_ptr(ssp_of_match),
704 .name = "sensorhub"
705 },
706};
707
708module_spi_driver(ssp_driver);
709
710MODULE_DESCRIPTION("ssp sensorhub driver");
711MODULE_AUTHOR("Samsung Electronics");
712MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c
new file mode 100644
index 000000000000..704284a475ae
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -0,0 +1,608 @@
1/*
2 * Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include "ssp.h"
17
18#define SSP_DEV (&data->spi->dev)
19#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW))
20
21/*
22 * SSP -> AP Instruction
23 * They tell what packet type can be expected. In the future there will
24 * be less of them. BYPASS means common sensor packets with accel, gyro,
25 * hrm etc. data. LIBRARY and META are mock-up's for now.
26 */
27#define SSP_MSG2AP_INST_BYPASS_DATA 0x37
28#define SSP_MSG2AP_INST_LIBRARY_DATA 0x01
29#define SSP_MSG2AP_INST_DEBUG_DATA 0x03
30#define SSP_MSG2AP_INST_BIG_DATA 0x04
31#define SSP_MSG2AP_INST_META_DATA 0x05
32#define SSP_MSG2AP_INST_TIME_SYNC 0x06
33#define SSP_MSG2AP_INST_RESET 0x07
34
35#define SSP_UNIMPLEMENTED -1
36
37struct ssp_msg_header {
38 u8 cmd;
39 __le16 length;
40 __le16 options;
41 __le32 data;
42} __attribute__((__packed__));
43
44struct ssp_msg {
45 u16 length;
46 u16 options;
47 struct list_head list;
48 struct completion *done;
49 struct ssp_msg_header *h;
50 char *buffer;
51};
52
53static const int ssp_offset_map[SSP_SENSOR_MAX] = {
54 [SSP_ACCELEROMETER_SENSOR] = SSP_ACCELEROMETER_SIZE +
55 SSP_TIME_SIZE,
56 [SSP_GYROSCOPE_SENSOR] = SSP_GYROSCOPE_SIZE +
57 SSP_TIME_SIZE,
58 [SSP_GEOMAGNETIC_UNCALIB_SENSOR] = SSP_UNIMPLEMENTED,
59 [SSP_GEOMAGNETIC_RAW] = SSP_UNIMPLEMENTED,
60 [SSP_GEOMAGNETIC_SENSOR] = SSP_UNIMPLEMENTED,
61 [SSP_PRESSURE_SENSOR] = SSP_UNIMPLEMENTED,
62 [SSP_GESTURE_SENSOR] = SSP_UNIMPLEMENTED,
63 [SSP_PROXIMITY_SENSOR] = SSP_UNIMPLEMENTED,
64 [SSP_TEMPERATURE_HUMIDITY_SENSOR] = SSP_UNIMPLEMENTED,
65 [SSP_LIGHT_SENSOR] = SSP_UNIMPLEMENTED,
66 [SSP_PROXIMITY_RAW] = SSP_UNIMPLEMENTED,
67 [SSP_ORIENTATION_SENSOR] = SSP_UNIMPLEMENTED,
68 [SSP_STEP_DETECTOR] = SSP_UNIMPLEMENTED,
69 [SSP_SIG_MOTION_SENSOR] = SSP_UNIMPLEMENTED,
70 [SSP_GYRO_UNCALIB_SENSOR] = SSP_UNIMPLEMENTED,
71 [SSP_GAME_ROTATION_VECTOR] = SSP_UNIMPLEMENTED,
72 [SSP_ROTATION_VECTOR] = SSP_UNIMPLEMENTED,
73 [SSP_STEP_COUNTER] = SSP_UNIMPLEMENTED,
74 [SSP_BIO_HRM_RAW] = SSP_BIO_HRM_RAW_SIZE +
75 SSP_TIME_SIZE,
76 [SSP_BIO_HRM_RAW_FAC] = SSP_BIO_HRM_RAW_FAC_SIZE +
77 SSP_TIME_SIZE,
78 [SSP_BIO_HRM_LIB] = SSP_BIO_HRM_LIB_SIZE +
79 SSP_TIME_SIZE,
80};
81
82#define SSP_HEADER_SIZE (sizeof(struct ssp_msg_header))
83#define SSP_HEADER_SIZE_ALIGNED (ALIGN(SSP_HEADER_SIZE, 4))
84
85static struct ssp_msg *ssp_create_msg(u8 cmd, u16 len, u16 opt, u32 data)
86{
87 struct ssp_msg_header h;
88 struct ssp_msg *msg;
89
90 msg = kzalloc(sizeof(*msg), GFP_KERNEL);
91 if (!msg)
92 return NULL;
93
94 h.cmd = cmd;
95 h.length = cpu_to_le16(len);
96 h.options = cpu_to_le16(opt);
97 h.data = cpu_to_le32(data);
98
99 msg->buffer = kzalloc(SSP_HEADER_SIZE_ALIGNED + len,
100 GFP_KERNEL | GFP_DMA);
101 if (!msg->buffer) {
102 kfree(msg);
103 return NULL;
104 }
105
106 msg->length = len;
107 msg->options = opt;
108
109 memcpy(msg->buffer, &h, SSP_HEADER_SIZE);
110
111 return msg;
112}
113
114/*
115 * It is a bit heavy to do it this way but often the function is used to compose
116 * the message from smaller chunks which are placed on the stack. Often the
117 * chunks are small so memcpy should be optimalized.
118 */
119static inline void ssp_fill_buffer(struct ssp_msg *m, unsigned int offset,
120 const void *src, unsigned int len)
121{
122 memcpy(&m->buffer[SSP_HEADER_SIZE_ALIGNED + offset], src, len);
123}
124
125static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset,
126 void *dest, unsigned int len)
127{
128 memcpy(dest, &m->buffer[SSP_HEADER_SIZE_ALIGNED + offset], len);
129}
130
131#define SSP_GET_BUFFER_AT_INDEX(m, index) \
132 (m->buffer[SSP_HEADER_SIZE_ALIGNED + index])
133#define SSP_SET_BUFFER_AT_INDEX(m, index, val) \
134 (m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val)
135
136static void ssp_clean_msg(struct ssp_msg *m)
137{
138 kfree(m->buffer);
139 kfree(m);
140}
141
142static int ssp_print_mcu_debug(char *data_frame, int *data_index,
143 int received_len)
144{
145 int length = data_frame[(*data_index)++];
146
147 if (length > received_len - *data_index || length <= 0) {
148 ssp_dbg("[SSP]: MSG From MCU-invalid debug length(%d/%d)\n",
149 length, received_len);
150 return length ? length : -EPROTO;
151 }
152
153 ssp_dbg("[SSP]: MSG From MCU - %s\n", &data_frame[*data_index]);
154
155 *data_index += length;
156
157 return 0;
158}
159
160/*
161 * It was designed that way - additional lines to some kind of handshake,
162 * please do not ask why - only the firmware guy can know it.
163 */
164static int ssp_check_lines(struct ssp_data *data, bool state)
165{
166 int delay_cnt = 0;
167
168 gpio_set_value_cansleep(data->ap_mcu_gpio, state);
169
170 while (gpio_get_value_cansleep(data->mcu_ap_gpio) != state) {
171 usleep_range(3000, 3500);
172
173 if (data->shut_down || delay_cnt++ > 500) {
174 dev_err(SSP_DEV, "%s:timeout, hw ack wait fail %d\n",
175 __func__, state);
176
177 if (!state)
178 gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
179
180 return -ETIMEDOUT;
181 }
182 }
183
184 return 0;
185}
186
187static int ssp_do_transfer(struct ssp_data *data, struct ssp_msg *msg,
188 struct completion *done, int timeout)
189{
190 int status;
191 /*
192 * check if this is a short one way message or the whole transfer has
193 * second part after an interrupt
194 */
195 const bool use_no_irq = msg->length == 0;
196
197 if (data->shut_down)
198 return -EPERM;
199
200 msg->done = done;
201
202 mutex_lock(&data->comm_lock);
203
204 status = ssp_check_lines(data, false);
205 if (status < 0)
206 goto _error_locked;
207
208 status = spi_write(data->spi, msg->buffer, SSP_HEADER_SIZE);
209 if (status < 0) {
210 gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
211 dev_err(SSP_DEV, "%s spi_write fail\n", __func__);
212 goto _error_locked;
213 }
214
215 if (!use_no_irq) {
216 mutex_lock(&data->pending_lock);
217 list_add_tail(&msg->list, &data->pending_list);
218 mutex_unlock(&data->pending_lock);
219 }
220
221 status = ssp_check_lines(data, true);
222 if (status < 0) {
223 if (!use_no_irq) {
224 mutex_lock(&data->pending_lock);
225 list_del(&msg->list);
226 mutex_unlock(&data->pending_lock);
227 }
228 goto _error_locked;
229 }
230
231 mutex_unlock(&data->comm_lock);
232
233 if (!use_no_irq && done)
234 if (wait_for_completion_timeout(done,
235 msecs_to_jiffies(timeout)) ==
236 0) {
237 mutex_lock(&data->pending_lock);
238 list_del(&msg->list);
239 mutex_unlock(&data->pending_lock);
240
241 data->timeout_cnt++;
242 return -ETIMEDOUT;
243 }
244
245 return 0;
246
247_error_locked:
248 mutex_unlock(&data->comm_lock);
249 data->timeout_cnt++;
250 return status;
251}
252
253static inline int ssp_spi_sync_command(struct ssp_data *data,
254 struct ssp_msg *msg)
255{
256 return ssp_do_transfer(data, msg, NULL, 0);
257}
258
259static int ssp_spi_sync(struct ssp_data *data, struct ssp_msg *msg,
260 int timeout)
261{
262 DECLARE_COMPLETION_ONSTACK(done);
263
264 if (WARN_ON(!msg->length))
265 return -EPERM;
266
267 return ssp_do_transfer(data, msg, &done, timeout);
268}
269
270static int ssp_handle_big_data(struct ssp_data *data, char *dataframe, int *idx)
271{
272 /* mock-up, it will be changed with adding another sensor types */
273 *idx += 8;
274 return 0;
275}
276
277static int ssp_parse_dataframe(struct ssp_data *data, char *dataframe, int len)
278{
279 int idx, sd;
280 struct timespec ts;
281 struct ssp_sensor_data *spd;
282 struct iio_dev **indio_devs = data->sensor_devs;
283
284 getnstimeofday(&ts);
285
286 for (idx = 0; idx < len;) {
287 switch (dataframe[idx++]) {
288 case SSP_MSG2AP_INST_BYPASS_DATA:
289 sd = dataframe[idx++];
290 if (sd < 0 || sd >= SSP_SENSOR_MAX) {
291 dev_err(SSP_DEV,
292 "Mcu data frame1 error %d\n", sd);
293 return -EPROTO;
294 }
295
296 if (indio_devs[sd]) {
297 spd = iio_priv(indio_devs[sd]);
298 if (spd->process_data)
299 spd->process_data(indio_devs[sd],
300 &dataframe[idx],
301 data->timestamp);
302 } else {
303 dev_err(SSP_DEV, "no client for frame\n");
304 }
305
306 idx += ssp_offset_map[sd];
307 break;
308 case SSP_MSG2AP_INST_DEBUG_DATA:
309 sd = ssp_print_mcu_debug(dataframe, &idx, len);
310 if (sd) {
311 dev_err(SSP_DEV,
312 "Mcu data frame3 error %d\n", sd);
313 return sd;
314 }
315 break;
316 case SSP_MSG2AP_INST_LIBRARY_DATA:
317 idx += len;
318 break;
319 case SSP_MSG2AP_INST_BIG_DATA:
320 ssp_handle_big_data(data, dataframe, &idx);
321 break;
322 case SSP_MSG2AP_INST_TIME_SYNC:
323 data->time_syncing = true;
324 break;
325 case SSP_MSG2AP_INST_RESET:
326 ssp_queue_ssp_refresh_task(data, 0);
327 break;
328 }
329 }
330
331 if (data->time_syncing)
332 data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
333
334 return 0;
335}
336
337/* threaded irq */
338int ssp_irq_msg(struct ssp_data *data)
339{
340 bool found = false;
341 char *buffer;
342 u8 msg_type;
343 int ret;
344 u16 length, msg_options;
345 struct ssp_msg *msg, *n;
346
347 ret = spi_read(data->spi, data->header_buffer, SSP_HEADER_BUFFER_SIZE);
348 if (ret < 0) {
349 dev_err(SSP_DEV, "header read fail\n");
350 return ret;
351 }
352
353 length = le16_to_cpu(data->header_buffer[1]);
354 msg_options = le16_to_cpu(data->header_buffer[0]);
355
356 if (length == 0) {
357 dev_err(SSP_DEV, "length received from mcu is 0\n");
358 return -EINVAL;
359 }
360
361 msg_type = SSP_GET_MESSAGE_TYPE(msg_options);
362
363 switch (msg_type) {
364 case SSP_AP2HUB_READ:
365 case SSP_AP2HUB_WRITE:
366 /*
367 * this is a small list, a few elements - the packets can be
368 * received with no order
369 */
370 mutex_lock(&data->pending_lock);
371 list_for_each_entry_safe(msg, n, &data->pending_list, list) {
372 if (msg->options == msg_options) {
373 list_del(&msg->list);
374 found = true;
375 break;
376 }
377 }
378
379 if (!found) {
380 /*
381 * here can be implemented dead messages handling
382 * but the slave should not send such ones - it is to
383 * check but let's handle this
384 */
385 buffer = kmalloc(length, GFP_KERNEL | GFP_DMA);
386 if (!buffer) {
387 ret = -ENOMEM;
388 goto _unlock;
389 }
390
391 /* got dead packet so it is always an error */
392 ret = spi_read(data->spi, buffer, length);
393 if (ret >= 0)
394 ret = -EPROTO;
395
396 kfree(buffer);
397
398 dev_err(SSP_DEV, "No match error %x\n",
399 msg_options);
400
401 goto _unlock;
402 }
403
404 if (msg_type == SSP_AP2HUB_READ)
405 ret = spi_read(data->spi,
406 &msg->buffer[SSP_HEADER_SIZE_ALIGNED],
407 msg->length);
408
409 if (msg_type == SSP_AP2HUB_WRITE) {
410 ret = spi_write(data->spi,
411 &msg->buffer[SSP_HEADER_SIZE_ALIGNED],
412 msg->length);
413 if (msg_options & SSP_AP2HUB_RETURN) {
414 msg->options =
415 SSP_AP2HUB_READ | SSP_AP2HUB_RETURN;
416 msg->length = 1;
417
418 list_add_tail(&msg->list, &data->pending_list);
419 goto _unlock;
420 }
421 }
422
423 if (msg->done)
424 if (!completion_done(msg->done))
425 complete(msg->done);
426_unlock:
427 mutex_unlock(&data->pending_lock);
428 break;
429 case SSP_HUB2AP_WRITE:
430 buffer = kzalloc(length, GFP_KERNEL | GFP_DMA);
431 if (!buffer)
432 return -ENOMEM;
433
434 ret = spi_read(data->spi, buffer, length);
435 if (ret < 0) {
436 dev_err(SSP_DEV, "spi read fail\n");
437 kfree(buffer);
438 break;
439 }
440
441 ret = ssp_parse_dataframe(data, buffer, length);
442
443 kfree(buffer);
444 break;
445
446 default:
447 dev_err(SSP_DEV, "unknown msg type\n");
448 return -EPROTO;
449 }
450
451 return ret;
452}
453
454void ssp_clean_pending_list(struct ssp_data *data)
455{
456 struct ssp_msg *msg, *n;
457
458 mutex_lock(&data->pending_lock);
459 list_for_each_entry_safe(msg, n, &data->pending_list, list) {
460 list_del(&msg->list);
461
462 if (msg->done)
463 if (!completion_done(msg->done))
464 complete(msg->done);
465 }
466 mutex_unlock(&data->pending_lock);
467}
468
469int ssp_command(struct ssp_data *data, char command, int arg)
470{
471 int ret;
472 struct ssp_msg *msg;
473
474 msg = ssp_create_msg(command, 0, SSP_AP2HUB_WRITE, arg);
475 if (!msg)
476 return -ENOMEM;
477
478 ssp_dbg("%s - command 0x%x %d\n", __func__, command, arg);
479
480 ret = ssp_spi_sync_command(data, msg);
481 ssp_clean_msg(msg);
482
483 return ret;
484}
485
486int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
487 u8 *send_buf, u8 length)
488{
489 int ret;
490 struct ssp_msg *msg;
491
492 if (data->fw_dl_state == SSP_FW_DL_STATE_DOWNLOADING) {
493 dev_err(SSP_DEV, "%s - Skip Inst! DL state = %d\n",
494 __func__, data->fw_dl_state);
495 return -EBUSY;
496 } else if (!(data->available_sensors & BIT(sensor_type)) &&
497 (inst <= SSP_MSG2SSP_INST_CHANGE_DELAY)) {
498 dev_err(SSP_DEV, "%s - Bypass Inst Skip! - %u\n",
499 __func__, sensor_type);
500 return -EIO; /* just fail */
501 }
502
503 msg = ssp_create_msg(inst, length + 2, SSP_AP2HUB_WRITE, 0);
504 if (!msg)
505 return -ENOMEM;
506
507 ssp_fill_buffer(msg, 0, &sensor_type, 1);
508 ssp_fill_buffer(msg, 1, send_buf, length);
509
510 ssp_dbg("%s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n",
511 __func__, inst, sensor_type, send_buf[1]);
512
513 ret = ssp_spi_sync(data, msg, 1000);
514 ssp_clean_msg(msg);
515
516 return ret;
517}
518
519int ssp_get_chipid(struct ssp_data *data)
520{
521 int ret;
522 char buffer;
523 struct ssp_msg *msg;
524
525 msg = ssp_create_msg(SSP_MSG2SSP_AP_WHOAMI, 1, SSP_AP2HUB_READ, 0);
526 if (!msg)
527 return -ENOMEM;
528
529 ret = ssp_spi_sync(data, msg, 1000);
530
531 buffer = SSP_GET_BUFFER_AT_INDEX(msg, 0);
532
533 ssp_clean_msg(msg);
534
535 return ret < 0 ? ret : buffer;
536}
537
538int ssp_set_magnetic_matrix(struct ssp_data *data)
539{
540 int ret;
541 struct ssp_msg *msg;
542
543 msg = ssp_create_msg(SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX,
544 data->sensorhub_info->mag_length, SSP_AP2HUB_WRITE,
545 0);
546 if (!msg)
547 return -ENOMEM;
548
549 ssp_fill_buffer(msg, 0, data->sensorhub_info->mag_table,
550 data->sensorhub_info->mag_length);
551
552 ret = ssp_spi_sync(data, msg, 1000);
553 ssp_clean_msg(msg);
554
555 return ret;
556}
557
558unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data)
559{
560 int ret;
561 __le32 result;
562 u32 cpu_result = 0;
563
564 struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_SENSOR_SCANNING, 4,
565 SSP_AP2HUB_READ, 0);
566 if (!msg)
567 return 0;
568
569 ret = ssp_spi_sync(data, msg, 1000);
570 if (ret < 0) {
571 dev_err(SSP_DEV, "%s - spi read fail %d\n", __func__, ret);
572 goto _exit;
573 }
574
575 ssp_get_buffer(msg, 0, &result, 4);
576 cpu_result = le32_to_cpu(result);
577
578 dev_info(SSP_DEV, "%s state: 0x%08x\n", __func__, cpu_result);
579
580_exit:
581 ssp_clean_msg(msg);
582 return cpu_result;
583}
584
585unsigned int ssp_get_firmware_rev(struct ssp_data *data)
586{
587 int ret;
588 __le32 result;
589
590 struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_FIRMWARE_REV, 4,
591 SSP_AP2HUB_READ, 0);
592 if (!msg)
593 return SSP_INVALID_REVISION;
594
595 ret = ssp_spi_sync(data, msg, 1000);
596 if (ret < 0) {
597 dev_err(SSP_DEV, "%s - transfer fail %d\n", __func__, ret);
598 ret = SSP_INVALID_REVISION;
599 goto _exit;
600 }
601
602 ssp_get_buffer(msg, 0, &result, 4);
603 ret = le32_to_cpu(result);
604
605_exit:
606 ssp_clean_msg(msg);
607 return ret;
608}