linux/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * cros_ec_lid_angle - Driver for CrOS EC lid angle sensor.
   5 *
   6 * Copyright 2018 Google, Inc
   7 *
   8 * This driver uses the cros-ec interface to communicate with the Chrome OS
   9 * EC about counter sensors. Counters are presented through
  10 * iio sysfs.
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/device.h>
  15#include <linux/iio/buffer.h>
  16#include <linux/iio/common/cros_ec_sensors_core.h>
  17#include <linux/iio/iio.h>
  18#include <linux/iio/kfifo_buf.h>
  19#include <linux/iio/trigger.h>
  20#include <linux/iio/triggered_buffer.h>
  21#include <linux/iio/trigger_consumer.h>
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/platform_data/cros_ec_commands.h>
  25#include <linux/platform_device.h>
  26#include <linux/slab.h>
  27
  28#define DRV_NAME "cros-ec-lid-angle"
  29
  30/*
  31 * One channel for the lid angle, the other for timestamp.
  32 */
  33static const struct iio_chan_spec cros_ec_lid_angle_channels[] = {
  34        {
  35                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  36                .scan_type.realbits = CROS_EC_SENSOR_BITS,
  37                .scan_type.storagebits = CROS_EC_SENSOR_BITS,
  38                .scan_type.sign = 'u',
  39                .type = IIO_ANGL
  40        },
  41        IIO_CHAN_SOFT_TIMESTAMP(1)
  42};
  43
  44/* State data for ec_sensors iio driver. */
  45struct cros_ec_lid_angle_state {
  46        /* Shared by all sensors */
  47        struct cros_ec_sensors_core_state core;
  48};
  49
  50static int cros_ec_sensors_read_lid_angle(struct iio_dev *indio_dev,
  51                                          unsigned long scan_mask, s16 *data)
  52{
  53        struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
  54        int ret;
  55
  56        st->param.cmd = MOTIONSENSE_CMD_LID_ANGLE;
  57        ret = cros_ec_motion_send_host_cmd(st, sizeof(st->resp->lid_angle));
  58        if (ret) {
  59                dev_warn(&indio_dev->dev, "Unable to read lid angle\n");
  60                return ret;
  61        }
  62
  63        *data = st->resp->lid_angle.value;
  64        return 0;
  65}
  66
  67static int cros_ec_lid_angle_read(struct iio_dev *indio_dev,
  68                                    struct iio_chan_spec const *chan,
  69                                    int *val, int *val2, long mask)
  70{
  71        struct cros_ec_lid_angle_state *st = iio_priv(indio_dev);
  72        s16 data;
  73        int ret;
  74
  75        mutex_lock(&st->core.cmd_lock);
  76        ret = cros_ec_sensors_read_lid_angle(indio_dev, 1, &data);
  77        if (ret == 0) {
  78                *val = data;
  79                ret = IIO_VAL_INT;
  80        }
  81        mutex_unlock(&st->core.cmd_lock);
  82        return ret;
  83}
  84
  85static const struct iio_info cros_ec_lid_angle_info = {
  86        .read_raw = &cros_ec_lid_angle_read,
  87};
  88
  89static int cros_ec_lid_angle_probe(struct platform_device *pdev)
  90{
  91        struct device *dev = &pdev->dev;
  92        struct iio_dev *indio_dev;
  93        struct cros_ec_lid_angle_state *state;
  94        int ret;
  95
  96        indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
  97        if (!indio_dev)
  98                return -ENOMEM;
  99
 100        ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL);
 101        if (ret)
 102                return ret;
 103
 104        indio_dev->info = &cros_ec_lid_angle_info;
 105        state = iio_priv(indio_dev);
 106        indio_dev->channels = cros_ec_lid_angle_channels;
 107        indio_dev->num_channels = ARRAY_SIZE(cros_ec_lid_angle_channels);
 108
 109        state->core.read_ec_sensors_data = cros_ec_sensors_read_lid_angle;
 110
 111        ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
 112                        cros_ec_sensors_capture, NULL);
 113        if (ret)
 114                return ret;
 115
 116        return devm_iio_device_register(dev, indio_dev);
 117}
 118
 119static const struct platform_device_id cros_ec_lid_angle_ids[] = {
 120        {
 121                .name = DRV_NAME,
 122        },
 123        { /* sentinel */ }
 124};
 125MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
 126
 127static struct platform_driver cros_ec_lid_angle_platform_driver = {
 128        .driver = {
 129                .name   = DRV_NAME,
 130        },
 131        .probe          = cros_ec_lid_angle_probe,
 132        .id_table       = cros_ec_lid_angle_ids,
 133};
 134module_platform_driver(cros_ec_lid_angle_platform_driver);
 135
 136MODULE_DESCRIPTION("ChromeOS EC driver for reporting convertible lid angle.");
 137MODULE_LICENSE("GPL v2");
 138