History

Merge tag 'tag-ib-chrome-mfd-iio-input-5.5' into chrome-platform-5.5

IB between mfd, iio, input and chrome platform for cros-ec-sensorhub

Enric Balletbo i Serra committed 6 years ago

Commit 5ec966d2 parents c2ce4d2 99cdb2417 files · +636 −421Browse files

Unified · Split

17 files
  1. drivers/iio/accel/cros_ec_accel_legacy.c +0 −6
  2. drivers/iio/common/cros_ec_sensors/Kconfig +1 −1
  3. drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +0 −6
  4. drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +3 −1
  5. drivers/iio/light/cros_ec_light_prox.c +0 −6
  6. drivers/input/keyboard/cros_ec_keyb.c +2 −4
  7. drivers/mfd/cros_ec_dev.c +12 −223
  8. drivers/platform/chrome/Kconfig +12 −0
  9. drivers/platform/chrome/Makefile +1 −0
  10. drivers/platform/chrome/cros_ec.c +76 −8
  11. drivers/platform/chrome/cros_ec_ishtp.c +19 −6
  12. drivers/platform/chrome/cros_ec_lpc.c +13 −4
  13. drivers/platform/chrome/cros_ec_proto.c +237 −30
  14. drivers/platform/chrome/cros_ec_rpmsg.c +4 −15
  15. drivers/platform/chrome/cros_ec_sensorhub.c +199 −0
  16. include/linux/platform_data/cros_ec_proto.h +27 −111
  17. include/linux/platform_data/cros_ec_sensorhub.h +30 −0
drivers/iio/accel/cros_ec_accel_legacy.c+0−6
@@ -163,16 +163,10 @@ static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = { · 162 unmodified lines
163static int cros_ec_accel_legacy_probe(struct platform_device *pdev)163static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
164{164{
165 struct device *dev = &pdev->dev;165 struct device *dev = &pdev->dev;
166 struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
167 struct iio_dev *indio_dev;166 struct iio_dev *indio_dev;
168 struct cros_ec_sensors_core_state *state;167 struct cros_ec_sensors_core_state *state;
169 int ret;168 int ret;
170 169
171 if (!ec || !ec->ec_dev) {
172 dev_warn(&pdev->dev, "No EC device found.\n");
173 return -EINVAL;
174 }
175
176 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));170 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
177 if (!indio_dev)171 if (!indio_dev)
178 return -ENOMEM;172 return -ENOMEM;
drivers/iio/common/cros_ec_sensors/Kconfig+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4#4#
5config IIO_CROS_EC_SENSORS_CORE5config IIO_CROS_EC_SENSORS_CORE
6 tristate "ChromeOS EC Sensors Core"6 tristate "ChromeOS EC Sensors Core"
7 depends on SYSFS && CROS_EC7 depends on SYSFS && CROS_EC_SENSORHUB
8 select IIO_BUFFER8 select IIO_BUFFER
9 select IIO_TRIGGERED_BUFFER9 select IIO_TRIGGERED_BUFFER
10 help10 help
drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c+0−6
@@ -222,17 +222,11 @@ static const struct iio_info ec_sensors_info = { · 221 unmodified lines
222static int cros_ec_sensors_probe(struct platform_device *pdev)222static int cros_ec_sensors_probe(struct platform_device *pdev)
223{223{
224 struct device *dev = &pdev->dev;224 struct device *dev = &pdev->dev;
225 struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
226 struct iio_dev *indio_dev;225 struct iio_dev *indio_dev;
227 struct cros_ec_sensors_state *state;226 struct cros_ec_sensors_state *state;
228 struct iio_chan_spec *channel;227 struct iio_chan_spec *channel;
229 int ret, i;228 int ret, i;
230 229
231 if (!ec_dev || !ec_dev->ec_dev) {
232 dev_warn(&pdev->dev, "No CROS EC device found.\n");
233 return -EINVAL;
234 }
235
236 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));230 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
237 if (!indio_dev)231 if (!indio_dev)
238 return -ENOMEM;232 return -ENOMEM;
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c+3−1
@@ -18,6 +18,7 @@ · 17 unmodified lines
18#include <linux/slab.h>18#include <linux/slab.h>
19#include <linux/platform_data/cros_ec_commands.h>19#include <linux/platform_data/cros_ec_commands.h>
20#include <linux/platform_data/cros_ec_proto.h>20#include <linux/platform_data/cros_ec_proto.h>
21#include <linux/platform_data/cros_ec_sensorhub.h>
21#include <linux/platform_device.h>22#include <linux/platform_device.h>
22 23
23static char *cros_ec_loc[] = {24static char *cros_ec_loc[] = {
@@ -88,7 +89,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, · 64 unmodified lines
88{89{
89 struct device *dev = &pdev->dev;90 struct device *dev = &pdev->dev;
90 struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);91 struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
91 struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);92 struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent);
93 struct cros_ec_dev *ec = sensor_hub->ec;
92 struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);94 struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
93 u32 ver_mask;95 u32 ver_mask;
94 int ret, i;96 int ret, i;
drivers/iio/light/cros_ec_light_prox.c+0−6
@@ -169,17 +169,11 @@ static const struct iio_info cros_ec_light_prox_info = { · 168 unmodified lines
169static int cros_ec_light_prox_probe(struct platform_device *pdev)169static int cros_ec_light_prox_probe(struct platform_device *pdev)
170{170{
171 struct device *dev = &pdev->dev;171 struct device *dev = &pdev->dev;
172 struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
173 struct iio_dev *indio_dev;172 struct iio_dev *indio_dev;
174 struct cros_ec_light_prox_state *state;173 struct cros_ec_light_prox_state *state;
175 struct iio_chan_spec *channel;174 struct iio_chan_spec *channel;
176 int ret;175 int ret;
177 176
178 if (!ec_dev || !ec_dev->ec_dev) {
179 dev_warn(dev, "No CROS EC device found.\n");
180 return -EINVAL;
181 }
182
183 indio_dev = devm_iio_device_alloc(dev, sizeof(*state));177 indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
184 if (!indio_dev)178 if (!indio_dev)
185 return -ENOMEM;179 return -ENOMEM;
drivers/input/keyboard/cros_ec_keyb.c+2−4
@@ -226,8 +226,6 @@ static int cros_ec_keyb_work(struct notifier_block *nb, · 225 unmodified lines
226{226{
227 struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,227 struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
228 notifier);228 notifier);
229 uint8_t mkbp_event_type = ckdev->ec->event_data.event_type &
230 EC_MKBP_EVENT_TYPE_MASK;
231 u32 val;229 u32 val;
232 unsigned int ev_type;230 unsigned int ev_type;
233 231
@@ -239,7 +237,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb, · 5 unmodified lines
239 if (queued_during_suspend && !device_may_wakeup(ckdev->dev))237 if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
240 return NOTIFY_OK;238 return NOTIFY_OK;
241 239
242 switch (mkbp_event_type) {240 switch (ckdev->ec->event_data.event_type) {
243 case EC_MKBP_EVENT_KEY_MATRIX:241 case EC_MKBP_EVENT_KEY_MATRIX:
244 pm_wakeup_event(ckdev->dev, 0);242 pm_wakeup_event(ckdev->dev, 0);
245 243
@@ -266,7 +264,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb, · 20 unmodified lines
266 case EC_MKBP_EVENT_SWITCH:264 case EC_MKBP_EVENT_SWITCH:
267 pm_wakeup_event(ckdev->dev, 0);265 pm_wakeup_event(ckdev->dev, 0);
268 266
269 if (mkbp_event_type == EC_MKBP_EVENT_BUTTON) {267 if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
270 val = get_unaligned_le32(268 val = get_unaligned_le32(
271 &ckdev->ec->event_data.data.buttons);269 &ckdev->ec->event_data.data.buttons);
272 ev_type = EV_KEY;270 ev_type = EV_KEY;
drivers/mfd/cros_ec_dev.c+12−223
@@ -78,6 +78,10 @@ static const struct mfd_cell cros_ec_rtc_cells[] = { · 77 unmodified lines
78 { .name = "cros-ec-rtc", },78 { .name = "cros-ec-rtc", },
79};79};
80 80
81static const struct mfd_cell cros_ec_sensorhub_cells[] = {
82 { .name = "cros-ec-sensorhub", },
83};
84
81static const struct mfd_cell cros_usbpd_charger_cells[] = {85static const struct mfd_cell cros_usbpd_charger_cells[] = {
82 { .name = "cros-usbpd-charger", },86 { .name = "cros-usbpd-charger", },
83 { .name = "cros-usbpd-logger", },87 { .name = "cros-usbpd-logger", },
@@ -112,229 +116,11 @@ static const struct mfd_cell cros_ec_vbc_cells[] = { · 28 unmodified lines
112 { .name = "cros-ec-vbc", }116 { .name = "cros-ec-vbc", }
113};117};
114 118
115static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
116{
117 struct cros_ec_command *msg;
118 int ret;
119
120 if (ec->features[0] == -1U && ec->features[1] == -1U) {
121 /* features bitmap not read yet */
122 msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
123 if (!msg)
124 return -ENOMEM;
125
126 msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
127 msg->insize = sizeof(ec->features);
128
129 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
130 if (ret < 0) {
131 dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
132 ret, msg->result);
133 memset(ec->features, 0, sizeof(ec->features));
134 } else {
135 memcpy(ec->features, msg->data, sizeof(ec->features));
136 }
137
138 dev_dbg(ec->dev, "EC features %08x %08x\n",
139 ec->features[0], ec->features[1]);
140
141 kfree(msg);
142 }
143
144 return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
145}
146
147static void cros_ec_class_release(struct device *dev)119static void cros_ec_class_release(struct device *dev)
148{120{
149 kfree(to_cros_ec_dev(dev));121 kfree(to_cros_ec_dev(dev));
150}122}
151 123
152static void cros_ec_sensors_register(struct cros_ec_dev *ec)
153{
154 /*
155 * Issue a command to get the number of sensor reported.
156 * Build an array of sensors driver and register them all.
157 */
158 int ret, i, id, sensor_num;
159 struct mfd_cell *sensor_cells;
160 struct cros_ec_sensor_platform *sensor_platforms;
161 int sensor_type[MOTIONSENSE_TYPE_MAX];
162 struct ec_params_motion_sense *params;
163 struct ec_response_motion_sense *resp;
164 struct cros_ec_command *msg;
165
166 msg = kzalloc(sizeof(struct cros_ec_command) +
167 max(sizeof(*params), sizeof(*resp)), GFP_KERNEL);
168 if (msg == NULL)
169 return;
170
171 msg->version = 2;
172 msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
173 msg->outsize = sizeof(*params);
174 msg->insize = sizeof(*resp);
175
176 params = (struct ec_params_motion_sense *)msg->data;
177 params->cmd = MOTIONSENSE_CMD_DUMP;
178
179 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
180 if (ret < 0) {
181 dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n",
182 ret, msg->result);
183 goto error;
184 }
185
186 resp = (struct ec_response_motion_sense *)msg->data;
187 sensor_num = resp->dump.sensor_count;
188 /*
189 * Allocate 2 extra sensors if lid angle sensor and/or FIFO are needed.
190 */
191 sensor_cells = kcalloc(sensor_num + 2, sizeof(struct mfd_cell),
192 GFP_KERNEL);
193 if (sensor_cells == NULL)
194 goto error;
195
196 sensor_platforms = kcalloc(sensor_num,
197 sizeof(struct cros_ec_sensor_platform),
198 GFP_KERNEL);
199 if (sensor_platforms == NULL)
200 goto error_platforms;
201
202 memset(sensor_type, 0, sizeof(sensor_type));
203 id = 0;
204 for (i = 0; i < sensor_num; i++) {
205 params->cmd = MOTIONSENSE_CMD_INFO;
206 params->info.sensor_num = i;
207 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
208 if (ret < 0) {
209 dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n",
210 i, ret, msg->result);
211 continue;
212 }
213 switch (resp->info.type) {
214 case MOTIONSENSE_TYPE_ACCEL:
215 sensor_cells[id].name = "cros-ec-accel";
216 break;
217 case MOTIONSENSE_TYPE_BARO:
218 sensor_cells[id].name = "cros-ec-baro";
219 break;
220 case MOTIONSENSE_TYPE_GYRO:
221 sensor_cells[id].name = "cros-ec-gyro";
222 break;
223 case MOTIONSENSE_TYPE_MAG:
224 sensor_cells[id].name = "cros-ec-mag";
225 break;
226 case MOTIONSENSE_TYPE_PROX:
227 sensor_cells[id].name = "cros-ec-prox";
228 break;
229 case MOTIONSENSE_TYPE_LIGHT:
230 sensor_cells[id].name = "cros-ec-light";
231 break;
232 case MOTIONSENSE_TYPE_ACTIVITY:
233 sensor_cells[id].name = "cros-ec-activity";
234 break;
235 default:
236 dev_warn(ec->dev, "unknown type %d\n", resp->info.type);
237 continue;
238 }
239 sensor_platforms[id].sensor_num = i;
240 sensor_cells[id].id = sensor_type[resp->info.type];
241 sensor_cells[id].platform_data = &sensor_platforms[id];
242 sensor_cells[id].pdata_size =
243 sizeof(struct cros_ec_sensor_platform);
244
245 sensor_type[resp->info.type]++;
246 id++;
247 }
248
249 if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
250 ec->has_kb_wake_angle = true;
251
252 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
253 sensor_cells[id].name = "cros-ec-ring";
254 id++;
255 }
256 if (cros_ec_check_features(ec,
257 EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
258 sensor_cells[id].name = "cros-ec-lid-angle";
259 id++;
260 }
261
262 ret = mfd_add_devices(ec->dev, 0, sensor_cells, id,
263 NULL, 0, NULL);
264 if (ret)
265 dev_err(ec->dev, "failed to add EC sensors\n");
266
267 kfree(sensor_platforms);
268error_platforms:
269 kfree(sensor_cells);
270error:
271 kfree(msg);
272}
273
274static struct cros_ec_sensor_platform sensor_platforms[] = {
275 { .sensor_num = 0 },
276 { .sensor_num = 1 }
277};
278
279static const struct mfd_cell cros_ec_accel_legacy_cells[] = {
280 {
281 .name = "cros-ec-accel-legacy",
282 .platform_data = &sensor_platforms[0],
283 .pdata_size = sizeof(struct cros_ec_sensor_platform),
284 },
285 {
286 .name = "cros-ec-accel-legacy",
287 .platform_data = &sensor_platforms[1],
288 .pdata_size = sizeof(struct cros_ec_sensor_platform),
289 }
290};
291
292static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec)
293{
294 struct cros_ec_device *ec_dev = ec->ec_dev;
295 u8 status;
296 int ret;
297
298 /*
299 * ECs that need legacy support are the main EC, directly connected to
300 * the AP.
301 */
302 if (ec->cmd_offset != 0)
303 return;
304
305 /*
306 * Check if EC supports direct memory reads and if EC has
307 * accelerometers.
308 */
309 if (ec_dev->cmd_readmem) {
310 ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, 1,
311 &status);
312 if (ret < 0) {
313 dev_warn(ec->dev, "EC direct read error.\n");
314 return;
315 }
316
317 /* Check if EC has accelerometers. */
318 if (!(status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
319 dev_info(ec->dev, "EC does not have accelerometers.\n");
320 return;
321 }
322 }
323
324 /*
325 * The device may still support accelerometers:
326 * it would be an older ARM based device that do not suppor the
327 * EC_CMD_GET_FEATURES command.
328 *
329 * Register 2 accelerometers, we will fail in the IIO driver if there
330 * are no sensors.
331 */
332 ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells,
333 ARRAY_SIZE(cros_ec_accel_legacy_cells));
334 if (ret)
335 dev_err(ec_dev->dev, "failed to add EC sensors\n");
336}
337
338static int ec_device_probe(struct platform_device *pdev)124static int ec_device_probe(struct platform_device *pdev)
339{125{
340 int retval = -ENOMEM;126 int retval = -ENOMEM;
@@ -390,11 +176,14 @@ static int ec_device_probe(struct platform_device *pdev) · 49 unmodified lines
390 goto failed;176 goto failed;
391 177
392 /* check whether this EC is a sensor hub. */178 /* check whether this EC is a sensor hub. */
393 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))179 if (cros_ec_get_sensor_count(ec) > 0) {
394 cros_ec_sensors_register(ec);180 retval = mfd_add_hotplug_devices(ec->dev,
395 else181 cros_ec_sensorhub_cells,
396 /* Workaroud for older EC firmware */182 ARRAY_SIZE(cros_ec_sensorhub_cells));
397 cros_ec_accel_legacy_register(ec);183 if (retval)
184 dev_err(ec->dev, "failed to add %s subdevice: %d\n",
185 cros_ec_sensorhub_cells->name, retval);
186 }
398 187
399 /*188 /*
400 * The following subdevices can be detected by sending the189 * The following subdevices can be detected by sending the
drivers/platform/chrome/Kconfig+12−0
@@ -190,6 +190,18 @@ config CROS_EC_DEBUGFS · 189 unmodified lines
190 To compile this driver as a module, choose M here: the190 To compile this driver as a module, choose M here: the
191 module will be called cros_ec_debugfs.191 module will be called cros_ec_debugfs.
192 192
193config CROS_EC_SENSORHUB
194 tristate "ChromeOS EC MEMS Sensor Hub"
195 depends on CROS_EC
196 help
197 Allow loading IIO sensors. This driver is loaded by MFD and will in
198 turn query the EC and register the sensors.
199 It also spreads the sensor data coming from the EC to the IIO sensor
200 object.
201
202 To compile this driver as a module, choose M here: the
203 module will be called cros_ec_sensorhub.
204
193config CROS_EC_SYSFS205config CROS_EC_SYSFS
194 tristate "ChromeOS EC control and information through sysfs"206 tristate "ChromeOS EC control and information through sysfs"
195 depends on MFD_CROS_EC_DEV && SYSFS207 depends on MFD_CROS_EC_DEV && SYSFS
drivers/platform/chrome/Makefile+1−0
@@ -19,6 +19,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o · 18 unmodified lines
19obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o19obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o
20obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o20obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o
21obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o21obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o
22obj-$(CONFIG_CROS_EC_SENSORHUB) += cros_ec_sensorhub.o
22obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o23obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o
23obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o24obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
24 25
drivers/platform/chrome/cros_ec.c+76−8
@@ -31,13 +31,32 @@ static struct cros_ec_platform pd_p = { · 30 unmodified lines
31 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),31 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
32};32};
33 33
34static irqreturn_t ec_irq_thread(int irq, void *data)34static irqreturn_t ec_irq_handler(int irq, void *data)
35{35{
36 struct cros_ec_device *ec_dev = data;36 struct cros_ec_device *ec_dev = data;
37 bool wake_event = true;37
38 ec_dev->last_event_time = cros_ec_get_time_ns();
39
40 return IRQ_WAKE_THREAD;
41}
42
43/**
44 * cros_ec_handle_event() - process and forward pending events on EC
45 * @ec_dev: Device with events to process.
46 *
47 * Call this function in a loop when the kernel is notified that the EC has
48 * pending events.
49 *
50 * Return: true if more events are still pending and this function should be
51 * called again.
52 */
53bool cros_ec_handle_event(struct cros_ec_device *ec_dev)
54{
55 bool wake_event;
56 bool ec_has_more_events;
38 int ret;57 int ret;
39 58
40 ret = cros_ec_get_next_event(ec_dev, &wake_event);59 ret = cros_ec_get_next_event(ec_dev, &wake_event, &ec_has_more_events);
41 60
42 /*61 /*
43 * Signal only if wake host events or any interrupt if62 * Signal only if wake host events or any interrupt if
@@ -50,6 +69,20 @@ static irqreturn_t ec_irq_thread(int irq, void *data) · 6 unmodified lines
50 if (ret > 0)69 if (ret > 0)
51 blocking_notifier_call_chain(&ec_dev->event_notifier,70 blocking_notifier_call_chain(&ec_dev->event_notifier,
52 0, ec_dev);71 0, ec_dev);
72
73 return ec_has_more_events;
74}
75EXPORT_SYMBOL(cros_ec_handle_event);
76
77static irqreturn_t ec_irq_thread(int irq, void *data)
78{
79 struct cros_ec_device *ec_dev = data;
80 bool ec_has_more_events;
81
82 do {
83 ec_has_more_events = cros_ec_handle_event(ec_dev);
84 } while (ec_has_more_events);
85
53 return IRQ_HANDLED;86 return IRQ_HANDLED;
54}87}
55 88
@@ -104,6 +137,15 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) · 48 unmodified lines
104 return ret;137 return ret;
105}138}
106 139
140/**
141 * cros_ec_register() - Register a new ChromeOS EC, using the provided info.
142 * @ec_dev: Device to register.
143 *
144 * Before calling this, allocate a pointer to a new device and then fill
145 * in all the fields up to the --private-- marker.
146 *
147 * Return: 0 on success or negative error code.
148 */
107int cros_ec_register(struct cros_ec_device *ec_dev)149int cros_ec_register(struct cros_ec_device *ec_dev)
108{150{
109 struct device *dev = ec_dev->dev;151 struct device *dev = ec_dev->dev;
@@ -131,10 +173,12 @@ int cros_ec_register(struct cros_ec_device *ec_dev) · 21 unmodified lines
131 return err;173 return err;
132 }174 }
133 175
134 if (ec_dev->irq) {176 if (ec_dev->irq > 0) {
135 err = devm_request_threaded_irq(dev, ec_dev->irq, NULL,177 err = devm_request_threaded_irq(dev, ec_dev->irq,
136 ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT,178 ec_irq_handler,
137 "chromeos-ec", ec_dev);179 ec_irq_thread,
180 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
181 "chromeos-ec", ec_dev);
138 if (err) {182 if (err) {
139 dev_err(dev, "Failed to request IRQ %d: %d",183 dev_err(dev, "Failed to request IRQ %d: %d",
140 ec_dev->irq, err);184 ec_dev->irq, err);
@@ -198,6 +242,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev) · 57 unmodified lines
198}242}
199EXPORT_SYMBOL(cros_ec_register);243EXPORT_SYMBOL(cros_ec_register);
200 244
245/**
246 * cros_ec_unregister() - Remove a ChromeOS EC.
247 * @ec_dev: Device to unregister.
248 *
249 * Call this to deregister a ChromeOS EC, then clean up any private data.
250 *
251 * Return: 0 on success or negative error code.
252 */
201int cros_ec_unregister(struct cros_ec_device *ec_dev)253int cros_ec_unregister(struct cros_ec_device *ec_dev)
202{254{
203 if (ec_dev->pd)255 if (ec_dev->pd)
@@ -209,6 +261,14 @@ int cros_ec_unregister(struct cros_ec_device *ec_dev) · 5 unmodified lines
209EXPORT_SYMBOL(cros_ec_unregister);261EXPORT_SYMBOL(cros_ec_unregister);
210 262
211#ifdef CONFIG_PM_SLEEP263#ifdef CONFIG_PM_SLEEP
264/**
265 * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
266 * @ec_dev: Device to suspend.
267 *
268 * This can be called by drivers to handle a suspend event.
269 *
270 * Return: 0 on success or negative error code.
271 */
212int cros_ec_suspend(struct cros_ec_device *ec_dev)272int cros_ec_suspend(struct cros_ec_device *ec_dev)
213{273{
214 struct device *dev = ec_dev->dev;274 struct device *dev = ec_dev->dev;
@@ -238,11 +298,19 @@ EXPORT_SYMBOL(cros_ec_suspend); · 23 unmodified lines
238static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)298static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
239{299{
240 while (ec_dev->mkbp_event_supported &&300 while (ec_dev->mkbp_event_supported &&
241 cros_ec_get_next_event(ec_dev, NULL) > 0)301 cros_ec_get_next_event(ec_dev, NULL, NULL) > 0)
242 blocking_notifier_call_chain(&ec_dev->event_notifier,302 blocking_notifier_call_chain(&ec_dev->event_notifier,
243 1, ec_dev);303 1, ec_dev);
244}304}
245 305
306/**
307 * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
308 * @ec_dev: Device to resume.
309 *
310 * This can be called by drivers to handle a resume event.
311 *
312 * Return: 0 on success or negative error code.
313 */
246int cros_ec_resume(struct cros_ec_device *ec_dev)314int cros_ec_resume(struct cros_ec_device *ec_dev)
247{315{
248 int ret;316 int ret;
drivers/platform/chrome/cros_ec_ishtp.c+19−6
@@ -136,11 +136,11 @@ static void ish_evt_handler(struct work_struct *work) · 135 unmodified lines
136 struct ishtp_cl_data *client_data =136 struct ishtp_cl_data *client_data =
137 container_of(work, struct ishtp_cl_data, work_ec_evt);137 container_of(work, struct ishtp_cl_data, work_ec_evt);
138 struct cros_ec_device *ec_dev = client_data->ec_dev;138 struct cros_ec_device *ec_dev = client_data->ec_dev;
139 bool ec_has_more_events;
139 140
140 if (cros_ec_get_next_event(ec_dev, NULL) > 0) {141 do {
141 blocking_notifier_call_chain(&ec_dev->event_notifier,142 ec_has_more_events = cros_ec_handle_event(ec_dev);
142 0, ec_dev);143 } while (ec_has_more_events);
143 }
144}144}
145 145
146/**146/**
@@ -200,13 +200,14 @@ static int ish_send(struct ishtp_cl_data *client_data, · 53 unmodified lines
200 * process_recv() - Received and parse incoming packet200 * process_recv() - Received and parse incoming packet
201 * @cros_ish_cl: Client instance to get stats201 * @cros_ish_cl: Client instance to get stats
202 * @rb_in_proc: Host interface message buffer202 * @rb_in_proc: Host interface message buffer
203 * @timestamp: Timestamp of when parent callback started
203 *204 *
204 * Parse the incoming packet. If it is a response packet then it will205 * Parse the incoming packet. If it is a response packet then it will
205 * update per instance flags and wake up the caller waiting to for the206 * update per instance flags and wake up the caller waiting to for the
206 * response. If it is an event packet then it will schedule event work.207 * response. If it is an event packet then it will schedule event work.
207 */208 */
208static void process_recv(struct ishtp_cl *cros_ish_cl,209static void process_recv(struct ishtp_cl *cros_ish_cl,
209 struct ishtp_cl_rb *rb_in_proc)210 struct ishtp_cl_rb *rb_in_proc, ktime_t timestamp)
210{211{
211 size_t data_len = rb_in_proc->buf_idx;212 size_t data_len = rb_in_proc->buf_idx;
212 struct ishtp_cl_data *client_data =213 struct ishtp_cl_data *client_data =
@@ -295,6 +296,11 @@ error_wake_up: · 82 unmodified lines
295 break;296 break;
296 297
297 case CROS_MKBP_EVENT:298 case CROS_MKBP_EVENT:
299 /*
300 * Set timestamp from beginning of function since we actually
301 * got an incoming MKBP event
302 */
303 client_data->ec_dev->last_event_time = timestamp;
298 /* The event system doesn't send any data in buffer */304 /* The event system doesn't send any data in buffer */
299 schedule_work(&client_data->work_ec_evt);305 schedule_work(&client_data->work_ec_evt);
300 306
@@ -322,10 +328,17 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device) · 21 unmodified lines
322{328{
323 struct ishtp_cl_rb *rb_in_proc;329 struct ishtp_cl_rb *rb_in_proc;
324 struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);330 struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
331 ktime_t timestamp;
332
333 /*
334 * Take timestamp as close to hardware interrupt as possible for sensor
335 * timestamps.
336 */
337 timestamp = cros_ec_get_time_ns();
325 338
326 while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {339 while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {
327 /* Decide what to do with received data */340 /* Decide what to do with received data */
328 process_recv(cros_ish_cl, rb_in_proc);341 process_recv(cros_ish_cl, rb_in_proc, timestamp);
329 }342 }
330}343}
331 344
drivers/platform/chrome/cros_ec_lpc.c+13−4
@@ -312,11 +312,20 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset, · 311 unmodified lines
312static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)312static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
313{313{
314 struct cros_ec_device *ec_dev = data;314 struct cros_ec_device *ec_dev = data;
315 bool ec_has_more_events;
316 int ret;
315 317
316 if (ec_dev->mkbp_event_supported &&318 ec_dev->last_event_time = cros_ec_get_time_ns();
317 cros_ec_get_next_event(ec_dev, NULL) > 0)319
318 blocking_notifier_call_chain(&ec_dev->event_notifier, 0,320 if (ec_dev->mkbp_event_supported)
319 ec_dev);321 do {
322 ret = cros_ec_get_next_event(ec_dev, NULL,
323 &ec_has_more_events);
324 if (ret > 0)
325 blocking_notifier_call_chain(
326 &ec_dev->event_notifier, 0,
327 ec_dev);
328 } while (ec_has_more_events);
320 329
321 if (value == ACPI_NOTIFY_DEVICE_WAKE)330 if (value == ACPI_NOTIFY_DEVICE_WAKE)
322 pm_system_wakeup();331 pm_system_wakeup();
drivers/platform/chrome/cros_ec_proto.c+237−30
@@ -117,6 +117,17 @@ static int send_command(struct cros_ec_device *ec_dev, · 116 unmodified lines
117 return ret;117 return ret;
118}118}
119 119
120/**
121 * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
122 * @ec_dev: Device to register.
123 * @msg: Message to write.
124 *
125 * This is intended to be used by all ChromeOS EC drivers, but at present
126 * only SPI uses it. Once LPC uses the same protocol it can start using it.
127 * I2C could use it now, with a refactor of the existing code.
128 *
129 * Return: 0 on success or negative error code.
130 */
120int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,131int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
121 struct cros_ec_command *msg)132 struct cros_ec_command *msg)
122{133{
@@ -141,6 +152,16 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, · 18 unmodified lines
141}152}
142EXPORT_SYMBOL(cros_ec_prepare_tx);153EXPORT_SYMBOL(cros_ec_prepare_tx);
143 154
155/**
156 * cros_ec_check_result() - Check ec_msg->result.
157 * @ec_dev: EC device.
158 * @msg: Message to check.
159 *
160 * This is used by ChromeOS EC drivers to check the ec_msg->result for
161 * errors and to warn about them.
162 *
163 * Return: 0 on success or negative error code.
164 */
144int cros_ec_check_result(struct cros_ec_device *ec_dev,165int cros_ec_check_result(struct cros_ec_device *ec_dev,
145 struct cros_ec_command *msg)166 struct cros_ec_command *msg)
146{167{
@@ -326,6 +347,13 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, · 179 unmodified lines
326 return ret;347 return ret;
327}348}
328 349
350/**
351 * cros_ec_query_all() - Query the protocol version supported by the
352 * ChromeOS EC.
353 * @ec_dev: Device to register.
354 *
355 * Return: 0 on success or negative error code.
356 */
329int cros_ec_query_all(struct cros_ec_device *ec_dev)357int cros_ec_query_all(struct cros_ec_device *ec_dev)
330{358{
331 struct device *dev = ec_dev->dev;359 struct device *dev = ec_dev->dev;
@@ -428,7 +456,10 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) · 96 unmodified lines
428 if (ret < 0 || ver_mask == 0)456 if (ret < 0 || ver_mask == 0)
429 ec_dev->mkbp_event_supported = 0;457 ec_dev->mkbp_event_supported = 0;
430 else458 else
431 ec_dev->mkbp_event_supported = 1;459 ec_dev->mkbp_event_supported = fls(ver_mask);
460
461 dev_dbg(ec_dev->dev, "MKBP support version %u\n",
462 ec_dev->mkbp_event_supported - 1);
432 463
433 /* Probe if host sleep v1 is supported for S0ix failure detection. */464 /* Probe if host sleep v1 is supported for S0ix failure detection. */
434 ret = cros_ec_get_host_command_version_mask(ec_dev,465 ret = cros_ec_get_host_command_version_mask(ec_dev,
@@ -453,6 +484,16 @@ exit: · 18 unmodified lines
453}484}
454EXPORT_SYMBOL(cros_ec_query_all);485EXPORT_SYMBOL(cros_ec_query_all);
455 486
487/**
488 * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
489 * @ec_dev: EC device.
490 * @msg: Message to write.
491 *
492 * Call this to send a command to the ChromeOS EC. This should be used
493 * instead of calling the EC's cmd_xfer() callback directly.
494 *
495 * Return: 0 on success or negative error code.
496 */
456int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,497int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
457 struct cros_ec_command *msg)498 struct cros_ec_command *msg)
458{499{
@@ -500,6 +541,18 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, · 41 unmodified lines
500}541}
501EXPORT_SYMBOL(cros_ec_cmd_xfer);542EXPORT_SYMBOL(cros_ec_cmd_xfer);
502 543
544/**
545 * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
546 * @ec_dev: EC device.
547 * @msg: Message to write.
548 *
549 * This function is identical to cros_ec_cmd_xfer, except it returns success
550 * status only if both the command was transmitted successfully and the EC
551 * replied with success status. It's not necessary to check msg->result when
552 * using this function.
553 *
554 * Return: The number of bytes transferred on success or negative error code.
555 */
503int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,556int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
504 struct cros_ec_command *msg)557 struct cros_ec_command *msg)
505{558{
@@ -519,6 +572,7 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer_status); · 13 unmodified lines
519 572
520static int get_next_event_xfer(struct cros_ec_device *ec_dev,573static int get_next_event_xfer(struct cros_ec_device *ec_dev,
521 struct cros_ec_command *msg,574 struct cros_ec_command *msg,
575 struct ec_response_get_next_event_v1 *event,
522 int version, uint32_t size)576 int version, uint32_t size)
523{577{
524 int ret;578 int ret;
@@ -531,7 +585,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev, · 6 unmodified lines
531 ret = cros_ec_cmd_xfer(ec_dev, msg);585 ret = cros_ec_cmd_xfer(ec_dev, msg);
532 if (ret > 0) {586 if (ret > 0) {
533 ec_dev->event_size = ret - 1;587 ec_dev->event_size = ret - 1;
534 memcpy(&ec_dev->event_data, msg->data, ret);588 ec_dev->event_data = *event;
535 }589 }
536 590
537 return ret;591 return ret;
@@ -539,30 +593,26 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev, · 1 unmodified line
539 593
540static int get_next_event(struct cros_ec_device *ec_dev)594static int get_next_event(struct cros_ec_device *ec_dev)
541{595{
542 u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];596 struct {
543 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;597 struct cros_ec_command msg;
544 static int cmd_version = 1;598 struct ec_response_get_next_event_v1 event;
545 int ret;599 } __packed buf;
600 struct cros_ec_command *msg = &buf.msg;
601 struct ec_response_get_next_event_v1 *event = &buf.event;
602 const int cmd_version = ec_dev->mkbp_event_supported - 1;
546 603
604 memset(msg, 0, sizeof(*msg));
547 if (ec_dev->suspended) {605 if (ec_dev->suspended) {
548 dev_dbg(ec_dev->dev, "Device suspended.\n");606 dev_dbg(ec_dev->dev, "Device suspended.\n");
549 return -EHOSTDOWN;607 return -EHOSTDOWN;
550 }608 }
551 609
552 if (cmd_version == 1) {610 if (cmd_version == 0)
553 ret = get_next_event_xfer(ec_dev, msg, cmd_version,611 return get_next_event_xfer(ec_dev, msg, event, 0,
554 sizeof(struct ec_response_get_next_event_v1));
555 if (ret < 0 || msg->result != EC_RES_INVALID_VERSION)
556 return ret;
557
558 /* Fallback to version 0 for future send attempts */
559 cmd_version = 0;
560 }
561
562 ret = get_next_event_xfer(ec_dev, msg, cmd_version,
563 sizeof(struct ec_response_get_next_event));612 sizeof(struct ec_response_get_next_event));
564 613
565 return ret;614 return get_next_event_xfer(ec_dev, msg, event, cmd_version,
615 sizeof(struct ec_response_get_next_event_v1));
566}616}
567 617
568static int get_keyboard_state_event(struct cros_ec_device *ec_dev)618static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
@@ -584,27 +634,60 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev) · 15 unmodified lines
584 return ec_dev->event_size;634 return ec_dev->event_size;
585}635}
586 636
587int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)637/**
638 * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
639 * @ec_dev: Device to fetch event from.
640 * @wake_event: Pointer to a bool set to true upon return if the event might be
641 * treated as a wake event. Ignored if null.
642 * @has_more_events: Pointer to bool set to true if more than one event is
643 * pending.
644 * Some EC will set this flag to indicate cros_ec_get_next_event()
645 * can be called multiple times in a row.
646 * It is an optimization to prevent issuing a EC command for
647 * nothing or wait for another interrupt from the EC to process
648 * the next message.
649 * Ignored if null.
650 *
651 * Return: negative error code on errors; 0 for no data; or else number of
652 * bytes received (i.e., an event was retrieved successfully). Event types are
653 * written out to @ec_dev->event_data.event_type on success.
654 */
655int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
656 bool *wake_event,
657 bool *has_more_events)
588{658{
589 u8 event_type;659 u8 event_type;
590 u32 host_event;660 u32 host_event;
591 int ret;661 int ret;
592 662
593 if (!ec_dev->mkbp_event_supported) {663 /*
594 ret = get_keyboard_state_event(ec_dev);664 * Default value for wake_event.
595 if (ret <= 0)665 * Wake up on keyboard event, wake up for spurious interrupt or link
596 return ret;666 * error to the EC.
667 */
668 if (wake_event)
669 *wake_event = true;
597 670
598 if (wake_event)671 /*
599 *wake_event = true;672 * Default value for has_more_events.
673 * EC will raise another interrupt if AP does not process all events
674 * anyway.
675 */
676 if (has_more_events)
677 *has_more_events = false;
600 678
601 return ret;679 if (!ec_dev->mkbp_event_supported)
602 }680 return get_keyboard_state_event(ec_dev);
603 681
604 ret = get_next_event(ec_dev);682 ret = get_next_event(ec_dev);
605 if (ret <= 0)683 if (ret <= 0)
606 return ret;684 return ret;
607 685
686 if (has_more_events)
687 *has_more_events = ec_dev->event_data.event_type &
688 EC_MKBP_HAS_MORE_EVENTS;
689 ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;
690
608 if (wake_event) {691 if (wake_event) {
609 event_type = ec_dev->event_data.event_type;692 event_type = ec_dev->event_data.event_type;
610 host_event = cros_ec_get_host_event(ec_dev);693 host_event = cros_ec_get_host_event(ec_dev);
@@ -619,15 +702,22 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event) · 8 unmodified lines
619 else if (host_event &&702 else if (host_event &&
620 !(host_event & ec_dev->host_event_wake_mask))703 !(host_event & ec_dev->host_event_wake_mask))
621 *wake_event = false;704 *wake_event = false;
622 /* Consider all other events as wake events. */
623 else
624 *wake_event = true;
625 }705 }
626 706
627 return ret;707 return ret;
628}708}
629EXPORT_SYMBOL(cros_ec_get_next_event);709EXPORT_SYMBOL(cros_ec_get_next_event);
630 710
711/**
712 * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
713 * @ec_dev: Device to fetch event from.
714 *
715 * When MKBP is supported, when the EC raises an interrupt, we collect the
716 * events raised and call the functions in the ec notifier. This function
717 * is a helper to know which events are raised.
718 *
719 * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
720 */
631u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)721u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
632{722{
633 u32 host_event;723 u32 host_event;
@@ -647,3 +737,120 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev) · 13 unmodified lines
647 return host_event;737 return host_event;
648}738}
649EXPORT_SYMBOL(cros_ec_get_host_event);739EXPORT_SYMBOL(cros_ec_get_host_event);
740
741/**
742 * cros_ec_check_features() - Test for the presence of EC features
743 *
744 * @ec: EC device, does not have to be connected directly to the AP,
745 * can be daisy chained through another device.
746 * @feature: One of ec_feature_code bit.
747 *
748 * Call this function to test whether the ChromeOS EC supports a feature.
749 *
750 * Return: 1 if supported, 0 if not
751 */
752int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
753{
754 struct cros_ec_command *msg;
755 int ret;
756
757 if (ec->features[0] == -1U && ec->features[1] == -1U) {
758 /* features bitmap not read yet */
759 msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
760 if (!msg)
761 return -ENOMEM;
762
763 msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
764 msg->insize = sizeof(ec->features);
765
766 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
767 if (ret < 0) {
768 dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
769 ret, msg->result);
770 memset(ec->features, 0, sizeof(ec->features));
771 } else {
772 memcpy(ec->features, msg->data, sizeof(ec->features));
773 }
774
775 dev_dbg(ec->dev, "EC features %08x %08x\n",
776 ec->features[0], ec->features[1]);
777
778 kfree(msg);
779 }
780
781 return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
782}
783EXPORT_SYMBOL_GPL(cros_ec_check_features);
784
785/**
786 * cros_ec_get_sensor_count() - Return the number of MEMS sensors supported.
787 *
788 * @ec: EC device, does not have to be connected directly to the AP,
789 * can be daisy chained through another device.
790 * Return: < 0 in case of error.
791 */
792int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
793{
794 /*
795 * Issue a command to get the number of sensor reported.
796 * If not supported, check for legacy mode.
797 */
798 int ret, sensor_count;
799 struct ec_params_motion_sense *params;
800 struct ec_response_motion_sense *resp;
801 struct cros_ec_command *msg;
802 struct cros_ec_device *ec_dev = ec->ec_dev;
803 u8 status;
804
805 msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
806 GFP_KERNEL);
807 if (!msg)
808 return -ENOMEM;
809
810 msg->version = 1;
811 msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
812 msg->outsize = sizeof(*params);
813 msg->insize = sizeof(*resp);
814
815 params = (struct ec_params_motion_sense *)msg->data;
816 params->cmd = MOTIONSENSE_CMD_DUMP;
817
818 ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
819 if (ret < 0) {
820 sensor_count = ret;
821 } else if (msg->result != EC_RES_SUCCESS) {
822 sensor_count = -EPROTO;
823 } else {
824 resp = (struct ec_response_motion_sense *)msg->data;
825 sensor_count = resp->dump.sensor_count;
826 }
827 kfree(msg);
828
829 /*
830 * Check legacy mode: Let's find out if sensors are accessible
831 * via LPC interface.
832 */
833 if (sensor_count == -EPROTO &&
834 ec->cmd_offset == 0 &&
835 ec_dev->cmd_readmem) {
836 ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,
837 1, &status);
838 if (ret >= 0 &&
839 (status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
840 /*
841 * We have 2 sensors, one in the lid, one in the base.
842 */
843 sensor_count = 2;
844 } else {
845 /*
846 * EC uses LPC interface and no sensors are presented.
847 */
848 sensor_count = 0;
849 }
850 } else if (sensor_count == -EPROTO) {
851 /* EC responded, but does not understand DUMP command. */
852 sensor_count = 0;
853 }
854 return sensor_count;
855}
856EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
drivers/platform/chrome/cros_ec_rpmsg.c+4−15
@@ -143,22 +143,11 @@ cros_ec_rpmsg_host_event_function(struct work_struct *host_event_work) · 142 unmodified lines
143 struct cros_ec_rpmsg,143 struct cros_ec_rpmsg,
144 host_event_work);144 host_event_work);
145 struct cros_ec_device *ec_dev = dev_get_drvdata(&ec_rpmsg->rpdev->dev);145 struct cros_ec_device *ec_dev = dev_get_drvdata(&ec_rpmsg->rpdev->dev);
146 bool wake_event = true;146 bool ec_has_more_events;
147 int ret;
148
149 ret = cros_ec_get_next_event(ec_dev, &wake_event);
150
151 /*
152 * Signal only if wake host events or any interrupt if
153 * cros_ec_get_next_event() returned an error (default value for
154 * wake_event is true)
155 */
156 if (wake_event && device_may_wakeup(ec_dev->dev))
157 pm_wakeup_event(ec_dev->dev, 0);
158 147
159 if (ret > 0)148 do {
160 blocking_notifier_call_chain(&ec_dev->event_notifier,149 ec_has_more_events = cros_ec_handle_event(ec_dev);
161 0, ec_dev);150 } while (ec_has_more_events);
162}151}
163 152
164static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,153static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
drivers/platform/chrome/cros_ec_sensorhub.c+199−0
@@ -0,0 +1,199 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Sensor HUB driver that discovers sensors behind a ChromeOS Embedded
4 * Controller.
5 *
6 * Copyright 2019 Google LLC
7 */
8
9#include <linux/init.h>
10#include <linux/device.h>
11#include <linux/module.h>
12#include <linux/mfd/cros_ec.h>
13#include <linux/platform_data/cros_ec_commands.h>
14#include <linux/platform_data/cros_ec_proto.h>
15#include <linux/platform_data/cros_ec_sensorhub.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18#include <linux/types.h>
19
20#define DRV_NAME "cros-ec-sensorhub"
21
22static void cros_ec_sensorhub_free_sensor(void *arg)
23{
24 struct platform_device *pdev = arg;
25
26 platform_device_unregister(pdev);
27}
28
29static int cros_ec_sensorhub_allocate_sensor(struct device *parent,
30 char *sensor_name,
31 int sensor_num)
32{
33 struct cros_ec_sensor_platform sensor_platforms = {
34 .sensor_num = sensor_num,
35 };
36 struct platform_device *pdev;
37
38 pdev = platform_device_register_data(parent, sensor_name,
39 PLATFORM_DEVID_AUTO,
40 &sensor_platforms,
41 sizeof(sensor_platforms));
42 if (IS_ERR(pdev))
43 return PTR_ERR(pdev);
44
45 return devm_add_action_or_reset(parent,
46 cros_ec_sensorhub_free_sensor,
47 pdev);
48}
49
50static int cros_ec_sensorhub_register(struct device *dev,
51 struct cros_ec_sensorhub *sensorhub)
52{
53 int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
54 struct cros_ec_dev *ec = sensorhub->ec;
55 struct ec_params_motion_sense *params;
56 struct ec_response_motion_sense *resp;
57 struct cros_ec_command *msg;
58 int ret, i, sensor_num;
59 char *name;
60
61 sensor_num = cros_ec_get_sensor_count(ec);
62 if (sensor_num < 0) {
63 dev_err(dev,
64 "Unable to retrieve sensor information (err:%d)\n",
65 sensor_num);
66 return sensor_num;
67 }
68
69 if (sensor_num == 0) {
70 dev_err(dev, "Zero sensors reported.\n");
71 return -EINVAL;
72 }
73
74 /* Prepare a message to send INFO command to each sensor. */
75 msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
76 GFP_KERNEL);
77 if (!msg)
78 return -ENOMEM;
79
80 msg->version = 1;
81 msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
82 msg->outsize = sizeof(*params);
83 msg->insize = sizeof(*resp);
84 params = (struct ec_params_motion_sense *)msg->data;
85 resp = (struct ec_response_motion_sense *)msg->data;
86
87 for (i = 0; i < sensor_num; i++) {
88 params->cmd = MOTIONSENSE_CMD_INFO;
89 params->info.sensor_num = i;
90
91 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
92 if (ret < 0) {
93 dev_warn(dev, "no info for EC sensor %d : %d/%d\n",
94 i, ret, msg->result);
95 continue;
96 }
97
98 switch (resp->info.type) {
99 case MOTIONSENSE_TYPE_ACCEL:
100 name = "cros-ec-accel";
101 break;
102 case MOTIONSENSE_TYPE_BARO:
103 name = "cros-ec-baro";
104 break;
105 case MOTIONSENSE_TYPE_GYRO:
106 name = "cros-ec-gyro";
107 break;
108 case MOTIONSENSE_TYPE_MAG:
109 name = "cros-ec-mag";
110 break;
111 case MOTIONSENSE_TYPE_PROX:
112 name = "cros-ec-prox";
113 break;
114 case MOTIONSENSE_TYPE_LIGHT:
115 name = "cros-ec-light";
116 break;
117 case MOTIONSENSE_TYPE_ACTIVITY:
118 name = "cros-ec-activity";
119 break;
120 default:
121 dev_warn(dev, "unknown type %d\n", resp->info.type);
122 continue;
123 }
124
125 ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
126 if (ret)
127 goto error;
128
129 sensor_type[resp->info.type]++;
130 }
131
132 if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
133 ec->has_kb_wake_angle = true;
134
135 if (cros_ec_check_features(ec,
136 EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
137 ret = cros_ec_sensorhub_allocate_sensor(dev,
138 "cros-ec-lid-angle",
139 0);
140 if (ret)
141 goto error;
142 }
143
144 kfree(msg);
145 return 0;
146
147error:
148 kfree(msg);
149 return ret;
150}
151
152static int cros_ec_sensorhub_probe(struct platform_device *pdev)
153{
154 struct device *dev = &pdev->dev;
155 struct cros_ec_sensorhub *data;
156 int ret;
157 int i;
158
159 data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
160 if (!data)
161 return -ENOMEM;
162
163 data->ec = dev_get_drvdata(dev->parent);
164 dev_set_drvdata(dev, data);
165
166 /* Check whether this EC is a sensor hub. */
167 if (cros_ec_check_features(data->ec, EC_FEATURE_MOTION_SENSE)) {
168 ret = cros_ec_sensorhub_register(dev, data);
169 if (ret)
170 return ret;
171 } else {
172 /*
173 * If the device has sensors but does not claim to
174 * be a sensor hub, we are in legacy mode.
175 */
176 for (i = 0; i < 2; i++) {
177 ret = cros_ec_sensorhub_allocate_sensor(dev,
178 "cros-ec-accel-legacy", i);
179 if (ret)
180 return ret;
181 }
182 }
183
184 return 0;
185}
186
187static struct platform_driver cros_ec_sensorhub_driver = {
188 .driver = {
189 .name = DRV_NAME,
190 },
191 .probe = cros_ec_sensorhub_probe,
192};
193
194module_platform_driver(cros_ec_sensorhub_driver);
195
196MODULE_ALIAS("platform:" DRV_NAME);
197MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
198MODULE_DESCRIPTION("ChromeOS EC MEMS Sensor Hub Driver");
199MODULE_LICENSE("GPL");
include/linux/platform_data/cros_ec_proto.h+27−111
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/mutex.h>12#include <linux/mutex.h>
13#include <linux/notifier.h>13#include <linux/notifier.h>
14 14
15#include <linux/mfd/cros_ec.h>
15#include <linux/platform_data/cros_ec_commands.h>16#include <linux/platform_data/cros_ec_commands.h>
16 17
17#define CROS_EC_DEV_NAME "cros_ec"18#define CROS_EC_DEV_NAME "cros_ec"
@@ -115,12 +116,16 @@ struct cros_ec_command { · 97 unmodified lines
115 * code.116 * code.
116 * @pkt_xfer: Send packet to EC and get response.117 * @pkt_xfer: Send packet to EC and get response.
117 * @lock: One transaction at a time.118 * @lock: One transaction at a time.
118 * @mkbp_event_supported: True if this EC supports the MKBP event protocol.119 * @mkbp_event_supported: 0 if MKBP not supported. Otherwise its value is
120 * the maximum supported version of the MKBP host event
121 * command + 1.
119 * @host_sleep_v1: True if this EC supports the sleep v1 command.122 * @host_sleep_v1: True if this EC supports the sleep v1 command.
120 * @event_notifier: Interrupt event notifier for transport devices.123 * @event_notifier: Interrupt event notifier for transport devices.
121 * @event_data: Raw payload transferred with the MKBP event.124 * @event_data: Raw payload transferred with the MKBP event.
122 * @event_size: Size in bytes of the event data.125 * @event_size: Size in bytes of the event data.
123 * @host_event_wake_mask: Mask of host events that cause wake from suspend.126 * @host_event_wake_mask: Mask of host events that cause wake from suspend.
127 * @last_event_time: exact time from the hard irq when we got notified of
128 * a new event.
124 * @ec: The platform_device used by the mfd driver to interface with the129 * @ec: The platform_device used by the mfd driver to interface with the
125 * main EC.130 * main EC.
126 * @pd: The platform_device used by the mfd driver to interface with the131 * @pd: The platform_device used by the mfd driver to interface with the
@@ -153,7 +158,7 @@ struct cros_ec_device { · 26 unmodified lines
153 int (*pkt_xfer)(struct cros_ec_device *ec,158 int (*pkt_xfer)(struct cros_ec_device *ec,
154 struct cros_ec_command *msg);159 struct cros_ec_command *msg);
155 struct mutex lock;160 struct mutex lock;
156 bool mkbp_event_supported;161 u8 mkbp_event_supported;
157 bool host_sleep_v1;162 bool host_sleep_v1;
158 struct blocking_notifier_head event_notifier;163 struct blocking_notifier_head event_notifier;
159 164
@@ -161,20 +166,13 @@ struct cros_ec_device { · 1 unmodified line
161 int event_size;166 int event_size;
162 u32 host_event_wake_mask;167 u32 host_event_wake_mask;
163 u32 last_resume_result;168 u32 last_resume_result;
169 ktime_t last_event_time;
164 170
165 /* The platform devices used by the mfd driver */171 /* The platform devices used by the mfd driver */
166 struct platform_device *ec;172 struct platform_device *ec;
167 struct platform_device *pd;173 struct platform_device *pd;
168};174};
169 175
170/**
171 * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
172 * @sensor_num: Id of the sensor, as reported by the EC.
173 */
174struct cros_ec_sensor_platform {
175 u8 sensor_num;
176};
177
178/**176/**
179 * struct cros_ec_platform - ChromeOS EC platform information.177 * struct cros_ec_platform - ChromeOS EC platform information.
180 * @ec_name: Name of EC device (e.g. 'cros-ec', 'cros-pd', ...)178 * @ec_name: Name of EC device (e.g. 'cros-ec', 'cros-pd', ...)
@@ -187,133 +185,51 @@ struct cros_ec_platform { · 6 unmodified lines
187 u16 cmd_offset;185 u16 cmd_offset;
188};186};
189 187
190/**
191 * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
192 * @ec_dev: Device to suspend.
193 *
194 * This can be called by drivers to handle a suspend event.
195 *
196 * Return: 0 on success or negative error code.
197 */
198int cros_ec_suspend(struct cros_ec_device *ec_dev);188int cros_ec_suspend(struct cros_ec_device *ec_dev);
199 189
200/**
201 * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
202 * @ec_dev: Device to resume.
203 *
204 * This can be called by drivers to handle a resume event.
205 *
206 * Return: 0 on success or negative error code.
207 */
208int cros_ec_resume(struct cros_ec_device *ec_dev);190int cros_ec_resume(struct cros_ec_device *ec_dev);
209 191
210/**
211 * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
212 * @ec_dev: Device to register.
213 * @msg: Message to write.
214 *
215 * This is intended to be used by all ChromeOS EC drivers, but at present
216 * only SPI uses it. Once LPC uses the same protocol it can start using it.
217 * I2C could use it now, with a refactor of the existing code.
218 *
219 * Return: 0 on success or negative error code.
220 */
221int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,192int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
222 struct cros_ec_command *msg);193 struct cros_ec_command *msg);
223 194
224/**
225 * cros_ec_check_result() - Check ec_msg->result.
226 * @ec_dev: EC device.
227 * @msg: Message to check.
228 *
229 * This is used by ChromeOS EC drivers to check the ec_msg->result for
230 * errors and to warn about them.
231 *
232 * Return: 0 on success or negative error code.
233 */
234int cros_ec_check_result(struct cros_ec_device *ec_dev,195int cros_ec_check_result(struct cros_ec_device *ec_dev,
235 struct cros_ec_command *msg);196 struct cros_ec_command *msg);
236 197
237/**
238 * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
239 * @ec_dev: EC device.
240 * @msg: Message to write.
241 *
242 * Call this to send a command to the ChromeOS EC. This should be used
243 * instead of calling the EC's cmd_xfer() callback directly.
244 *
245 * Return: 0 on success or negative error code.
246 */
247int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,198int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
248 struct cros_ec_command *msg);199 struct cros_ec_command *msg);
249 200
250/**
251 * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
252 * @ec_dev: EC device.
253 * @msg: Message to write.
254 *
255 * This function is identical to cros_ec_cmd_xfer, except it returns success
256 * status only if both the command was transmitted successfully and the EC
257 * replied with success status. It's not necessary to check msg->result when
258 * using this function.
259 *
260 * Return: The number of bytes transferred on success or negative error code.
261 */
262int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,201int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
263 struct cros_ec_command *msg);202 struct cros_ec_command *msg);
264 203
265/**
266 * cros_ec_register() - Register a new ChromeOS EC, using the provided info.
267 * @ec_dev: Device to register.
268 *
269 * Before calling this, allocate a pointer to a new device and then fill
270 * in all the fields up to the --private-- marker.
271 *
272 * Return: 0 on success or negative error code.
273 */
274int cros_ec_register(struct cros_ec_device *ec_dev);204int cros_ec_register(struct cros_ec_device *ec_dev);
275 205
276/**
277 * cros_ec_unregister() - Remove a ChromeOS EC.
278 * @ec_dev: Device to unregister.
279 *
280 * Call this to deregister a ChromeOS EC, then clean up any private data.
281 *
282 * Return: 0 on success or negative error code.
283 */
284int cros_ec_unregister(struct cros_ec_device *ec_dev);206int cros_ec_unregister(struct cros_ec_device *ec_dev);
285 207
286/**
287 * cros_ec_query_all() - Query the protocol version supported by the
288 * ChromeOS EC.
289 * @ec_dev: Device to register.
290 *
291 * Return: 0 on success or negative error code.
292 */
293int cros_ec_query_all(struct cros_ec_device *ec_dev);208int cros_ec_query_all(struct cros_ec_device *ec_dev);
294 209
295/**210int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
296 * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.211 bool *wake_event,
297 * @ec_dev: Device to fetch event from.212 bool *has_more_events);
298 * @wake_event: Pointer to a bool set to true upon return if the event might be213
299 * treated as a wake event. Ignored if null.214u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
300 *215
301 * Return: negative error code on errors; 0 for no data; or else number of216int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
302 * bytes received (i.e., an event was retrieved successfully). Event types are217
303 * written out to @ec_dev->event_data.event_type on success.218int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
304 */219
305int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);220bool cros_ec_handle_event(struct cros_ec_device *ec_dev);
306 221
307/**222/**
308 * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.223 * cros_ec_get_time_ns() - Return time in ns.
309 * @ec_dev: Device to fetch event from.
310 *224 *
311 * When MKBP is supported, when the EC raises an interrupt, we collect the225 * This is the function used to record the time for last_event_time in struct
312 * events raised and call the functions in the ec notifier. This function226 * cros_ec_device during the hard irq.
313 * is a helper to know which events are raised.
314 *227 *
315 * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.228 * Return: ktime_t format since boot.
316 */229 */
317u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);230static inline ktime_t cros_ec_get_time_ns(void)
231{
232 return ktime_get_boottime_ns();
233}
318 234
319#endif /* __LINUX_CROS_EC_PROTO_H */235#endif /* __LINUX_CROS_EC_PROTO_H */
include/linux/platform_data/cros_ec_sensorhub.h+30−0
@@ -0,0 +1,30 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Chrome OS EC MEMS Sensor Hub driver.
4 *
5 * Copyright 2019 Google LLC
6 */
7
8#ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
9#define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
10
11#include <linux/platform_data/cros_ec_commands.h>
12
13/**
14 * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
15 * @sensor_num: Id of the sensor, as reported by the EC.
16 */
17struct cros_ec_sensor_platform {
18 u8 sensor_num;
19};
20
21/**
22 * struct cros_ec_sensorhub - Sensor Hub device data.
23 *
24 * @ec: Embedded Controller where the hub is located.
25 */
26struct cros_ec_sensorhub {
27 struct cros_ec_dev *ec;
28};
29
30#endif /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t