xref: /linux/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c (revision 0d5ec7919f3747193f051036b2301734a4b5e1d6)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cros_ec_activity - Driver for activities/gesture recognition.
4  *
5  * Copyright 2025 Google, Inc
6  *
7  * This driver uses the cros-ec interface to communicate with the ChromeOS
8  * EC about activity data.
9  */
10 
11 #include <linux/bits.h>
12 #include <linux/cleanup.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/platform_device.h>
17 #include <linux/types.h>
18 
19 #include <linux/platform_data/cros_ec_commands.h>
20 #include <linux/platform_data/cros_ec_proto.h>
21 
22 #include <linux/iio/common/cros_ec_sensors_core.h>
23 #include <linux/iio/events.h>
24 #include <linux/iio/iio.h>
25 #include <linux/iio/trigger_consumer.h>
26 
27 #define DRV_NAME "cros-ec-activity"
28 
29 /* state data for ec_sensors iio driver. */
30 struct cros_ec_sensors_state {
31 	/* Shared by all sensors */
32 	struct cros_ec_sensors_core_state core;
33 
34 	struct iio_chan_spec *channels;
35 
36 	int body_detection_channel_index;
37 	int sig_motion_channel_index;
38 };
39 
40 static const struct iio_event_spec cros_ec_activity_single_shot[] = {
41 	{
42 		.type = IIO_EV_TYPE_CHANGE,
43 		/* significant motion trigger when we get out of still. */
44 		.dir = IIO_EV_DIR_FALLING,
45 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
46 	},
47 };
48 
49 static const struct iio_event_spec cros_ec_body_detect_events[] = {
50 	{
51 		.type = IIO_EV_TYPE_CHANGE,
52 		.dir = IIO_EV_DIR_EITHER,
53 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
54 	},
55 };
56 
cros_ec_activity_sensors_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)57 static int cros_ec_activity_sensors_read_raw(struct iio_dev *indio_dev,
58 					     struct iio_chan_spec const *chan,
59 					     int *val, int *val2, long mask)
60 {
61 	struct cros_ec_sensors_state *st = iio_priv(indio_dev);
62 	int ret;
63 
64 	if (chan->type != IIO_PROXIMITY || mask != IIO_CHAN_INFO_RAW)
65 		return -EINVAL;
66 
67 	guard(mutex)(&st->core.cmd_lock);
68 	st->core.param.cmd = MOTIONSENSE_CMD_GET_ACTIVITY;
69 	st->core.param.get_activity.activity =
70 		MOTIONSENSE_ACTIVITY_BODY_DETECTION;
71 	ret = cros_ec_motion_send_host_cmd(&st->core, 0);
72 	if (ret)
73 		return ret;
74 
75 	/*
76 	 * EC actually report if a body is near (1) or far (0).
77 	 * Units for proximity sensor after scale is in meter,
78 	 * so invert the result to return 0m when near and 1m when far.
79 	 */
80 	*val = !st->core.resp->get_activity.state;
81 	return IIO_VAL_INT;
82 }
83 
cros_ec_activity_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)84 static int cros_ec_activity_read_event_config(struct iio_dev *indio_dev,
85 					      const struct iio_chan_spec *chan,
86 					      enum iio_event_type type,
87 					      enum iio_event_direction dir)
88 {
89 	struct cros_ec_sensors_state *st = iio_priv(indio_dev);
90 	int ret;
91 
92 	if (chan->type != IIO_ACTIVITY && chan->type != IIO_PROXIMITY)
93 		return -EINVAL;
94 
95 	guard(mutex)(&st->core.cmd_lock);
96 	st->core.param.cmd = MOTIONSENSE_CMD_LIST_ACTIVITIES;
97 	ret = cros_ec_motion_send_host_cmd(&st->core, 0);
98 	if (ret)
99 		return ret;
100 
101 	switch (chan->type) {
102 	case IIO_PROXIMITY:
103 		return !!(st->core.resp->list_activities.enabled &
104 			 (1 << MOTIONSENSE_ACTIVITY_BODY_DETECTION));
105 	case IIO_ACTIVITY:
106 		if (chan->channel2 == IIO_MOD_STILL) {
107 			return !!(st->core.resp->list_activities.enabled &
108 				 (1 << MOTIONSENSE_ACTIVITY_SIG_MOTION));
109 		}
110 
111 		dev_warn(&indio_dev->dev, "Unknown activity: %d\n",
112 			 chan->channel2);
113 		return -EINVAL;
114 	default:
115 		dev_warn(&indio_dev->dev, "Unknown channel type: %d\n",
116 			 chan->type);
117 		return -EINVAL;
118 	}
119 }
120 
cros_ec_activity_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,bool state)121 static int cros_ec_activity_write_event_config(struct iio_dev *indio_dev,
122 					       const struct iio_chan_spec *chan,
123 					       enum iio_event_type type,
124 					       enum iio_event_direction dir,
125 					       bool state)
126 {
127 	struct cros_ec_sensors_state *st = iio_priv(indio_dev);
128 
129 	guard(mutex)(&st->core.cmd_lock);
130 	st->core.param.cmd = MOTIONSENSE_CMD_SET_ACTIVITY;
131 	switch (chan->type) {
132 	case IIO_PROXIMITY:
133 		st->core.param.set_activity.activity =
134 			MOTIONSENSE_ACTIVITY_BODY_DETECTION;
135 		break;
136 	case IIO_ACTIVITY:
137 		if (chan->channel2 == IIO_MOD_STILL) {
138 			st->core.param.set_activity.activity =
139 				MOTIONSENSE_ACTIVITY_SIG_MOTION;
140 			break;
141 		}
142 		dev_warn(&indio_dev->dev, "Unknown activity: %d\n",
143 			 chan->channel2);
144 		return -EINVAL;
145 	default:
146 		dev_warn(&indio_dev->dev, "Unknown channel type: %d\n",
147 			 chan->type);
148 		return -EINVAL;
149 	}
150 	st->core.param.set_activity.enable = state;
151 	return cros_ec_motion_send_host_cmd(&st->core, 0);
152 }
153 
cros_ec_activity_push_data(struct iio_dev * indio_dev,s16 * data,s64 timestamp)154 static int cros_ec_activity_push_data(struct iio_dev *indio_dev,
155 				      s16 *data, s64 timestamp)
156 {
157 	struct ec_response_activity_data *activity_data =
158 			(struct ec_response_activity_data *)data;
159 	enum motionsensor_activity activity = activity_data->activity;
160 	u8 state = activity_data->state;
161 	const struct cros_ec_sensors_state *st = iio_priv(indio_dev);
162 	const struct iio_chan_spec *chan;
163 	enum iio_event_direction dir;
164 	int index;
165 
166 	switch (activity) {
167 	case MOTIONSENSE_ACTIVITY_BODY_DETECTION:
168 		index = st->body_detection_channel_index;
169 		dir = state ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
170 		break;
171 	case MOTIONSENSE_ACTIVITY_SIG_MOTION:
172 		index = st->sig_motion_channel_index;
173 		dir = IIO_EV_DIR_FALLING;
174 		break;
175 	default:
176 		dev_warn(&indio_dev->dev, "Unknown activity: %d\n", activity);
177 		return 0;
178 	}
179 	chan = &st->channels[index];
180 	iio_push_event(indio_dev,
181 		       IIO_UNMOD_EVENT_CODE(chan->type, index, chan->event_spec[0].type, dir),
182 		       timestamp);
183 	return 0;
184 }
185 
cros_ec_activity_capture(int irq,void * p)186 static irqreturn_t cros_ec_activity_capture(int irq, void *p)
187 {
188 	struct iio_poll_func *pf = p;
189 	struct iio_dev *indio_dev = pf->indio_dev;
190 
191 	/*
192 	 * This callback would be called when a software trigger is
193 	 * used. But when this virtual sensor is present, it is guaranteed
194 	 * the sensor hub is advanced enough to not need a software trigger.
195 	 */
196 	dev_warn(&indio_dev->dev, "%s: Not Expected\n", __func__);
197 	return IRQ_NONE;
198 }
199 
200 static const struct iio_info ec_sensors_info = {
201 	.read_raw = &cros_ec_activity_sensors_read_raw,
202 	.read_event_config = cros_ec_activity_read_event_config,
203 	.write_event_config = cros_ec_activity_write_event_config,
204 };
205 
cros_ec_sensors_probe(struct platform_device * pdev)206 static int cros_ec_sensors_probe(struct platform_device *pdev)
207 {
208 	struct device *dev = &pdev->dev;
209 	struct cros_ec_device *ec_device = dev_get_drvdata(dev->parent);
210 	struct iio_dev *indio_dev;
211 	struct cros_ec_sensors_state *st;
212 	struct iio_chan_spec *channel;
213 	unsigned long activities;
214 	int i, index, ret, nb_activities;
215 
216 	if (!ec_device) {
217 		dev_warn(dev, "No CROS EC device found.\n");
218 		return -EINVAL;
219 	}
220 
221 	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
222 	if (!indio_dev)
223 		return -ENOMEM;
224 
225 	ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
226 					cros_ec_activity_capture);
227 	if (ret)
228 		return ret;
229 
230 	indio_dev->info = &ec_sensors_info;
231 	st = iio_priv(indio_dev);
232 	st->core.type = st->core.resp->info.type;
233 	st->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
234 
235 	st->core.param.cmd = MOTIONSENSE_CMD_LIST_ACTIVITIES;
236 	ret = cros_ec_motion_send_host_cmd(&st->core, 0);
237 	if (ret)
238 		return ret;
239 
240 	activities = st->core.resp->list_activities.enabled |
241 		     st->core.resp->list_activities.disabled;
242 	if (!activities)
243 		return -ENODEV;
244 
245 	/* Allocate a channel per activity and one for timestamp */
246 	nb_activities = hweight_long(activities) + 1;
247 	st->channels = devm_kcalloc(dev, nb_activities,
248 				    sizeof(*st->channels), GFP_KERNEL);
249 	if (!st->channels)
250 		return -ENOMEM;
251 
252 	channel = &st->channels[0];
253 	index = 0;
254 	for_each_set_bit(i, &activities, BITS_PER_LONG) {
255 		/* List all available triggers */
256 		if (i == MOTIONSENSE_ACTIVITY_BODY_DETECTION) {
257 			channel->type = IIO_PROXIMITY;
258 			channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
259 			channel->event_spec = cros_ec_body_detect_events;
260 			channel->num_event_specs =
261 				ARRAY_SIZE(cros_ec_body_detect_events);
262 			st->body_detection_channel_index = index;
263 		} else {
264 			channel->type = IIO_ACTIVITY;
265 			channel->modified = 1;
266 			channel->event_spec = cros_ec_activity_single_shot;
267 			channel->num_event_specs =
268 				ARRAY_SIZE(cros_ec_activity_single_shot);
269 			if (i == MOTIONSENSE_ACTIVITY_SIG_MOTION) {
270 				channel->channel2 = IIO_MOD_STILL;
271 				st->sig_motion_channel_index = index;
272 			} else {
273 				dev_warn(dev, "Unknown activity: %d\n", i);
274 				continue;
275 			}
276 		}
277 		channel->ext_info = cros_ec_sensors_limited_info;
278 		channel->scan_index = index++;
279 		channel++;
280 	}
281 
282 	/* Timestamp */
283 	channel->scan_index = index;
284 	channel->type = IIO_TIMESTAMP;
285 	channel->channel = -1;
286 	channel->scan_type.sign = 's';
287 	channel->scan_type.realbits = 64;
288 	channel->scan_type.storagebits = 64;
289 
290 	indio_dev->channels = st->channels;
291 	indio_dev->num_channels = index + 1;
292 
293 	return cros_ec_sensors_core_register(dev, indio_dev,
294 					     cros_ec_activity_push_data);
295 }
296 
297 static struct platform_driver cros_ec_sensors_platform_driver = {
298 	.driver = {
299 		.name	= DRV_NAME,
300 	},
301 	.probe		= cros_ec_sensors_probe,
302 };
303 module_platform_driver(cros_ec_sensors_platform_driver);
304 
305 MODULE_DESCRIPTION("ChromeOS EC activity sensors driver");
306 MODULE_ALIAS("platform:" DRV_NAME);
307 MODULE_LICENSE("GPL v2");
308