mirror of https://gitee.com/openkylin/linux.git
chrome platform changes for 5.7
* cros-usbpd-notify and cros_ec_typec - Add a new notification driver that handles and dispatches USB PD related events to other drivers. - Add a Type C connector class driver for cros_ec * CrOS EC - Introduce a new cros_ec_cmd_xfer_status helper * Sensors/iio: - A series from Gwendal that adds Cros EC sensor hub FIFO support * Wilco EC - Fix a build warning. - Platform data shouldn't include kernel.h * Misc - i2c api conversion complete, with i2c_new_client_device instead of i2c_new_device in chromeos_laptop. - Replace zero-length array with flexible-array member in cros_ec_chardev and wilco_ec - Update new structure for SPI transfer delays in cros_ec_spi -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQCtZK6p/AktxXfkOlzbaomhzOwwgUCXo1lfQAKCRBzbaomhzOw wo6TAQCKHOcrqq5Y9HYXs1QBx8e/0vVwe5Jh76Qi6hUVqXu56QEA65lBZ2ni8Udp f6jQDFkaeYaF2tkghvuNoAkFRI6/rAk= =j4Tt -----END PGP SIGNATURE----- Merge tag 'tag-chrome-platform-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux Pull chrome platform updates from Benson Leung: cros-usbpd-notify and cros_ec_typec: - Add a new notification driver that handles and dispatches USB PD related events to other drivers. - Add a Type C connector class driver for cros_ec CrOS EC: - Introduce a new cros_ec_cmd_xfer_status helper Sensors/iio: - A series from Gwendal that adds Cros EC sensor hub FIFO support Wilco EC: - Fix a build warning. - Platform data shouldn't include kernel.h Misc: - i2c api conversion complete, with i2c_new_client_device instead of i2c_new_device in chromeos_laptop. - Replace zero-length array with flexible-array member in cros_ec_chardev and wilco_ec - Update new structure for SPI transfer delays in cros_ec_spi * tag 'tag-chrome-platform-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (34 commits) platform/chrome: cros_ec_spi: Wait for USECS, not NSECS iio: cros_ec: Use Hertz as unit for sampling frequency iio: cros_ec: Report hwfifo_watermark_max iio: cros_ec: Expose hwfifo_timeout iio: cros_ec: Remove pm function iio: cros_ec: Register to cros_ec_sensorhub when EC supports FIFO iio: expose iio_device_set_clock iio: cros_ec: Move function description to .c file platform/chrome: cros_ec_sensorhub: Add median filter platform/chrome: cros_ec_sensorhub: Add code to spread timestmap platform/chrome: cros_ec_sensorhub: Add FIFO support platform/chrome: cros_ec_sensorhub: Add the number of sensors in sensorhub platform/chrome: chromeos_laptop: make I2C API conversion complete platform/chrome: wilco_ec: event: Replace zero-length array with flexible-array member platform/chrome: cros_ec_chardev: Replace zero-length array with flexible-array member platform/chrome: cros_ec_typec: Update port info from EC platform/chrome: Add Type C connector class driver platform/chrome: cros_usbpd_notify: Pull PD_HOST_EVENT status platform/chrome: cros_usbpd_notify: Amend ACPI driver to plat platform/chrome: cros_usbpd_notify: Add driver data struct ...
This commit is contained in:
commit
413a103cf6
|
@ -170,7 +170,8 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -190,11 +191,6 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
|
|||
state->sign[CROS_EC_SENSOR_Z] = -1;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, false);
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -127,7 +127,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
|
|||
static struct platform_driver cros_ec_lid_angle_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = &cros_ec_sensors_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_lid_angle_probe,
|
||||
.id_table = cros_ec_lid_angle_ids,
|
||||
|
|
|
@ -230,10 +230,14 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
|
||||
cros_ec_sensors_capture,
|
||||
cros_ec_sensors_push_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
|
||||
|
||||
indio_dev->info = &ec_sensors_info;
|
||||
state = iio_priv(indio_dev);
|
||||
for (channel = state->channels, i = CROS_EC_SENSOR_X;
|
||||
|
@ -245,7 +249,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
|
|||
BIT(IIO_CHAN_INFO_CALIBSCALE);
|
||||
channel->info_mask_shared_by_all =
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_FREQUENCY) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
channel->info_mask_shared_by_all_available =
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
|
@ -292,11 +295,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
|
|||
else
|
||||
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
|
@ -317,7 +315,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
|
|||
static struct platform_driver cros_ec_sensors_platform_driver = {
|
||||
.driver = {
|
||||
.name = "cros-ec-sensors",
|
||||
.pm = &cros_ec_sensors_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_sensors_probe,
|
||||
.id_table = cros_ec_sensors_ids,
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <linux/iio/common/cros_ec_sensors_core.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -20,6 +22,12 @@
|
|||
#include <linux/platform_data/cros_ec_sensorhub.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* Hard coded to the first device to support sensor fifo. The EC has a 2048
|
||||
* byte fifo and will trigger an interrupt when fifo is 2/3 full.
|
||||
*/
|
||||
#define CROS_EC_FIFO_SIZE (2048 * 2 / 3)
|
||||
|
||||
static char *cros_ec_loc[] = {
|
||||
[MOTIONSENSE_LOC_BASE] = "base",
|
||||
[MOTIONSENSE_LOC_LID] = "lid",
|
||||
|
@ -53,8 +61,15 @@ static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev,
|
|||
|
||||
static void get_default_min_max_freq(enum motionsensor_type type,
|
||||
u32 *min_freq,
|
||||
u32 *max_freq)
|
||||
u32 *max_freq,
|
||||
u32 *max_fifo_events)
|
||||
{
|
||||
/*
|
||||
* We don't know fifo size, set to size previously used by older
|
||||
* hardware.
|
||||
*/
|
||||
*max_fifo_events = CROS_EC_FIFO_SIZE;
|
||||
|
||||
switch (type) {
|
||||
case MOTIONSENSE_TYPE_ACCEL:
|
||||
case MOTIONSENSE_TYPE_GYRO:
|
||||
|
@ -82,9 +97,155 @@ static void get_default_min_max_freq(enum motionsensor_type type,
|
|||
}
|
||||
}
|
||||
|
||||
static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st,
|
||||
int rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rate > U16_MAX)
|
||||
rate = U16_MAX;
|
||||
|
||||
mutex_lock(&st->cmd_lock);
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data = rate;
|
||||
ret = cros_ec_motion_send_host_cmd(st, 0);
|
||||
mutex_unlock(&st->cmd_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t cros_ec_sensor_set_report_latency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
int integer, fract, ret;
|
||||
int latency;
|
||||
|
||||
ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* EC rate is in ms. */
|
||||
latency = integer * 1000 + fract / 1000;
|
||||
ret = cros_ec_sensor_set_ec_rate(st, latency);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t cros_ec_sensor_get_report_latency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
int latency, ret;
|
||||
|
||||
mutex_lock(&st->cmd_lock);
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE;
|
||||
|
||||
ret = cros_ec_motion_send_host_cmd(st, 0);
|
||||
latency = st->resp->ec_rate.ret;
|
||||
mutex_unlock(&st->cmd_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d.%06u\n",
|
||||
latency / 1000,
|
||||
(latency % 1000) * 1000);
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
|
||||
cros_ec_sensor_get_report_latency,
|
||||
cros_ec_sensor_set_report_latency, 0);
|
||||
|
||||
static ssize_t hwfifo_watermark_max_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
|
||||
return sprintf(buf, "%d\n", st->fifo_max_event_count);
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
|
||||
|
||||
const struct attribute *cros_ec_sensor_fifo_attributes[] = {
|
||||
&iio_dev_attr_hwfifo_timeout.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensor_fifo_attributes);
|
||||
|
||||
int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
|
||||
s16 *data,
|
||||
s64 timestamp)
|
||||
{
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
s16 *out;
|
||||
s64 delta;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Ignore samples if the buffer is not set: it is needed if the ODR is
|
||||
* set but the buffer is not enabled yet.
|
||||
*/
|
||||
if (!iio_buffer_enabled(indio_dev))
|
||||
return 0;
|
||||
|
||||
out = (s16 *)st->samples;
|
||||
for_each_set_bit(i,
|
||||
indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
*out = data[i];
|
||||
out++;
|
||||
}
|
||||
|
||||
if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME)
|
||||
delta = iio_get_time_ns(indio_dev) - cros_ec_get_time_ns();
|
||||
else
|
||||
delta = 0;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->samples,
|
||||
timestamp + delta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_push_data);
|
||||
|
||||
static void cros_ec_sensors_core_clean(void *arg)
|
||||
{
|
||||
struct platform_device *pdev = (struct platform_device *)arg;
|
||||
struct cros_ec_sensorhub *sensor_hub =
|
||||
dev_get_drvdata(pdev->dev.parent);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
u8 sensor_num = st->param.info.sensor_num;
|
||||
|
||||
cros_ec_sensorhub_unregister_push_data(sensor_hub, sensor_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_init() - basic initialization of the core structure
|
||||
* @pdev: platform device created for the sensors
|
||||
* @indio_dev: iio device structure of the device
|
||||
* @physical_device: true if the device refers to a physical device
|
||||
* @trigger_capture: function pointer to call buffer is triggered,
|
||||
* for backward compatibility.
|
||||
* @push_data: function to call when cros_ec_sensorhub receives
|
||||
* a sample for that sensor.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_core_init(struct platform_device *pdev,
|
||||
struct iio_dev *indio_dev,
|
||||
bool physical_device)
|
||||
bool physical_device,
|
||||
cros_ec_sensors_capture_t trigger_capture,
|
||||
cros_ec_sensorhub_push_data_cb_t push_data)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
|
||||
|
@ -92,6 +253,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
|
|||
struct cros_ec_dev *ec = sensor_hub->ec;
|
||||
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
|
||||
u32 ver_mask;
|
||||
int frequencies[ARRAY_SIZE(state->frequencies) / 2] = { 0 };
|
||||
int ret, i;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
@ -123,8 +285,6 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
|
|||
indio_dev->name = pdev->name;
|
||||
|
||||
if (physical_device) {
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
state->param.cmd = MOTIONSENSE_CMD_INFO;
|
||||
state->param.info.sensor_num = sensor_platform->sensor_num;
|
||||
ret = cros_ec_motion_send_host_cmd(state, 0);
|
||||
|
@ -142,16 +302,63 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
|
|||
state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE;
|
||||
|
||||
/* 0 is a correct value used to stop the device */
|
||||
state->frequencies[0] = 0;
|
||||
if (state->msg->version < 3) {
|
||||
get_default_min_max_freq(state->resp->info.type,
|
||||
&state->frequencies[1],
|
||||
&state->frequencies[2]);
|
||||
&frequencies[1],
|
||||
&frequencies[2],
|
||||
&state->fifo_max_event_count);
|
||||
} else {
|
||||
state->frequencies[1] =
|
||||
state->resp->info_3.min_frequency;
|
||||
state->frequencies[2] =
|
||||
state->resp->info_3.max_frequency;
|
||||
frequencies[1] = state->resp->info_3.min_frequency;
|
||||
frequencies[2] = state->resp->info_3.max_frequency;
|
||||
state->fifo_max_event_count =
|
||||
state->resp->info_3.fifo_max_event_count;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(frequencies); i++) {
|
||||
state->frequencies[2 * i] = frequencies[i] / 1000;
|
||||
state->frequencies[2 * i + 1] =
|
||||
(frequencies[i] % 1000) * 1000;
|
||||
}
|
||||
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
|
||||
/*
|
||||
* Create a software buffer, feed by the EC FIFO.
|
||||
* We can not use trigger here, as events are generated
|
||||
* as soon as sample_frequency is set.
|
||||
*/
|
||||
struct iio_buffer *buffer;
|
||||
|
||||
buffer = devm_iio_kfifo_allocate(dev);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
indio_dev->modes = INDIO_BUFFER_SOFTWARE;
|
||||
|
||||
ret = cros_ec_sensorhub_register_push_data(
|
||||
sensor_hub, sensor_platform->sensor_num,
|
||||
indio_dev, push_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(
|
||||
dev, cros_ec_sensors_core_clean, pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Timestamp coming from FIFO are in ns since boot. */
|
||||
ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/*
|
||||
* The only way to get samples in buffer is to set a
|
||||
* software tigger (systrig, hrtimer).
|
||||
*/
|
||||
ret = devm_iio_triggered_buffer_setup(
|
||||
dev, indio_dev, NULL, trigger_capture,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,6 +366,16 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_init);
|
||||
|
||||
/**
|
||||
* cros_ec_motion_send_host_cmd() - send motion sense host command
|
||||
* @state: pointer to state information for device
|
||||
* @opt_length: optional length to reduce the response size, useful on the data
|
||||
* path. Otherwise, the maximal allowed response size is used
|
||||
*
|
||||
* When called, the sub-command is assumed to be set in param->cmd.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state,
|
||||
u16 opt_length)
|
||||
{
|
||||
|
@ -421,6 +638,14 @@ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_read_lpc);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol
|
||||
* @indio_dev: pointer to IIO device
|
||||
* @scan_mask: bitmap of the sensor indices to scan
|
||||
* @data: location to store data
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev,
|
||||
unsigned long scan_mask, s16 *data)
|
||||
{
|
||||
|
@ -445,6 +670,18 @@ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_read_cmd);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_capture() - the trigger handler function
|
||||
* @irq: the interrupt number.
|
||||
* @p: a pointer to the poll function.
|
||||
*
|
||||
* On a trigger event occurring, if the pollfunc is attached then this
|
||||
* handler is called as a threaded interrupt (and hence may sleep). It
|
||||
* is responsible for grabbing data from the device and pushing it into
|
||||
* the associated buffer.
|
||||
*
|
||||
* Return: IRQ_HANDLED
|
||||
*/
|
||||
irqreturn_t cros_ec_sensors_capture(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
|
@ -480,26 +717,24 @@ irqreturn_t cros_ec_sensors_capture(int irq, void *p)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_capture);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_read() - function to request a value from the sensor
|
||||
* @st: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @val: will contain one element making up the returned value
|
||||
* @val2: will contain another element making up the returned value
|
||||
* @mask: specifies which values to be requested
|
||||
*
|
||||
* Return: the type of value returned by the device
|
||||
*/
|
||||
int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
int ret, frequency;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data =
|
||||
EC_MOTION_SENSE_NO_VALUE;
|
||||
|
||||
ret = cros_ec_motion_send_host_cmd(st, 0);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
*val = st->resp->ec_rate.ret;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_FREQUENCY:
|
||||
st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
|
||||
st->param.sensor_odr.data =
|
||||
EC_MOTION_SENSE_NO_VALUE;
|
||||
|
@ -508,8 +743,10 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
|
|||
if (ret)
|
||||
break;
|
||||
|
||||
*val = st->resp->sensor_odr.ret;
|
||||
ret = IIO_VAL_INT;
|
||||
frequency = st->resp->sensor_odr.ret;
|
||||
*val = frequency / 1000;
|
||||
*val2 = (frequency % 1000) * 1000;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -520,6 +757,17 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_read_avail() - get available values
|
||||
* @indio_dev: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @vals: list of available values
|
||||
* @type: type of data returned
|
||||
* @length: number of data returned in the array
|
||||
* @mask: specifies which values to be requested
|
||||
*
|
||||
* Return: an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST
|
||||
*/
|
||||
int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals,
|
||||
|
@ -533,7 +781,7 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*length = ARRAY_SIZE(state->frequencies);
|
||||
*vals = (const int *)&state->frequencies;
|
||||
*type = IIO_VAL_INT;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
return IIO_AVAIL_LIST;
|
||||
}
|
||||
|
||||
|
@ -541,31 +789,33 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_write() - function to write a value to the sensor
|
||||
* @st: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @val: first part of value to write
|
||||
* @val2: second part of value to write
|
||||
* @mask: specifies which values to write
|
||||
*
|
||||
* Return: the type of value returned by the device
|
||||
*/
|
||||
int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
int ret, frequency;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_FREQUENCY:
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
frequency = val * 1000 + val2 / 1000;
|
||||
st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
|
||||
st->param.sensor_odr.data = val;
|
||||
st->param.sensor_odr.data = frequency;
|
||||
|
||||
/* Always roundup, so caller gets at least what it asks for. */
|
||||
st->param.sensor_odr.roundup = 1;
|
||||
|
||||
ret = cros_ec_motion_send_host_cmd(st, 0);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data = val;
|
||||
|
||||
ret = cros_ec_motion_send_host_cmd(st, 0);
|
||||
if (ret)
|
||||
break;
|
||||
st->curr_sampl_freq = val;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
|
@ -574,52 +824,5 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write);
|
||||
|
||||
static int __maybe_unused cros_ec_sensors_prepare(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->curr_sampl_freq == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the sensors are sampled at high frequency, we will not be able to
|
||||
* sleep. Set sampling to a long period if necessary.
|
||||
*/
|
||||
if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
|
||||
mutex_lock(&st->cmd_lock);
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data = CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY;
|
||||
cros_ec_motion_send_host_cmd(st, 0);
|
||||
mutex_unlock(&st->cmd_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __maybe_unused cros_ec_sensors_complete(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->curr_sampl_freq == 0)
|
||||
return;
|
||||
|
||||
if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
|
||||
mutex_lock(&st->cmd_lock);
|
||||
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
|
||||
st->param.ec_rate.data = st->curr_sampl_freq;
|
||||
cros_ec_motion_send_host_cmd(st, 0);
|
||||
mutex_unlock(&st->cmd_lock);
|
||||
}
|
||||
}
|
||||
|
||||
const struct dev_pm_ops cros_ec_sensors_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.prepare = cros_ec_sensors_prepare,
|
||||
.complete = cros_ec_sensors_complete
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops);
|
||||
|
||||
MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -189,7 +189,12 @@ ssize_t iio_read_const_attr(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL(iio_read_const_attr);
|
||||
|
||||
static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
|
||||
/**
|
||||
* iio_device_set_clock() - Set current timestamping clock for the device
|
||||
* @indio_dev: IIO device structure containing the device
|
||||
* @clock_id: timestamping clock posix identifier to set.
|
||||
*/
|
||||
int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
|
||||
{
|
||||
int ret;
|
||||
const struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
|
@ -207,6 +212,7 @@ static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_device_set_clock);
|
||||
|
||||
/**
|
||||
* iio_get_time_ns() - utility function to get a time stamp for events etc
|
||||
|
|
|
@ -177,10 +177,14 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
|
||||
cros_ec_sensors_capture,
|
||||
cros_ec_sensors_push_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
|
||||
|
||||
indio_dev->info = &cros_ec_light_prox_info;
|
||||
state = iio_priv(indio_dev);
|
||||
state->core.type = state->core.resp->info.type;
|
||||
|
@ -189,8 +193,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
|
|||
|
||||
/* Common part */
|
||||
channel->info_mask_shared_by_all =
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_FREQUENCY);
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
channel->info_mask_shared_by_all_available =
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
|
||||
|
@ -236,11 +239,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
|
|||
|
||||
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
|
@ -258,7 +256,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
|
|||
static struct platform_driver cros_ec_light_prox_platform_driver = {
|
||||
.driver = {
|
||||
.name = "cros-ec-light-prox",
|
||||
.pm = &cros_ec_sensors_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_light_prox_probe,
|
||||
.id_table = cros_ec_light_prox_ids,
|
||||
|
|
|
@ -134,10 +134,14 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
|
||||
cros_ec_sensors_capture,
|
||||
cros_ec_sensors_push_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
|
||||
|
||||
indio_dev->info = &cros_ec_baro_info;
|
||||
state = iio_priv(indio_dev);
|
||||
state->core.type = state->core.resp->info.type;
|
||||
|
@ -147,8 +151,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
|
|||
channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
channel->info_mask_shared_by_all =
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_FREQUENCY);
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
channel->info_mask_shared_by_all_available =
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
|
||||
|
@ -182,11 +185,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
|
|||
|
||||
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ config MFD_CROS_EC
|
|||
tristate "Platform support for Chrome hardware (transitional)"
|
||||
select CHROME_PLATFORMS
|
||||
select CROS_EC
|
||||
select CONFIG_MFD_CROS_EC_DEV
|
||||
select MFD_CROS_EC_DEV
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
help
|
||||
This is a transitional Kconfig option and will be removed after
|
||||
|
@ -214,6 +214,17 @@ config CROS_EC_SYSFS
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_ec_sysfs.
|
||||
|
||||
config CROS_EC_TYPEC
|
||||
tristate "ChromeOS EC Type-C Connector Control"
|
||||
depends on MFD_CROS_EC_DEV && TYPEC
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
If you say Y here, you get support for accessing Type C connector
|
||||
information from the Chrome OS EC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called cros_ec_typec.
|
||||
|
||||
config CROS_USBPD_LOGGER
|
||||
tristate "Logging driver for USB PD charger"
|
||||
depends on CHARGER_CROS_USBPD
|
||||
|
@ -226,6 +237,20 @@ config CROS_USBPD_LOGGER
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_usbpd_logger.
|
||||
|
||||
config CROS_USBPD_NOTIFY
|
||||
tristate "ChromeOS Type-C power delivery event notifier"
|
||||
depends on MFD_CROS_EC_DEV
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
If you say Y here, you get support for Type-C PD event notifications
|
||||
from the ChromeOS EC. On ACPI platorms this driver will bind to the
|
||||
GOOG0003 ACPI device, and on platforms which don't have this device it
|
||||
will get initialized on ECs which support the feature
|
||||
EC_FEATURE_USB_PD.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_usbpd_notify.
|
||||
|
||||
source "drivers/platform/chrome/wilco_ec/Kconfig"
|
||||
|
||||
endif # CHROMEOS_PLATFORMS
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o
|
|||
obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o
|
||||
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
|
||||
cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o
|
||||
obj-$(CONFIG_CROS_EC_TYPEC) += cros_ec_typec.o
|
||||
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
|
||||
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o
|
||||
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
|
||||
|
@ -19,8 +20,10 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o
|
|||
obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o
|
||||
obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o
|
||||
obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o
|
||||
obj-$(CONFIG_CROS_EC_SENSORHUB) += cros_ec_sensorhub.o
|
||||
cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o
|
||||
obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o
|
||||
obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o
|
||||
obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
|
||||
obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
|
||||
|
||||
obj-$(CONFIG_WILCO_EC) += wilco_ec/
|
||||
|
|
|
@ -103,7 +103,7 @@ chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
|
|||
pr_debug("%d-%02x is probed at %02x\n",
|
||||
adapter->nr, info->addr, dummy->addr);
|
||||
i2c_unregister_device(dummy);
|
||||
client = i2c_new_device(adapter, info);
|
||||
client = i2c_new_client_device(adapter, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
|||
|
||||
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
|
||||
|
||||
/* For now, report failure to transition to S0ix with a warning. */
|
||||
if (ret >= 0 && ec_dev->host_sleep_v1 &&
|
||||
|
@ -138,6 +138,24 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_ready_event(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend,
|
||||
void *_notify)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = container_of(nb, struct cros_ec_device,
|
||||
notifier_ready);
|
||||
u32 host_event = cros_ec_get_host_event(ec_dev);
|
||||
|
||||
if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INTERFACE_READY)) {
|
||||
mutex_lock(&ec_dev->lock);
|
||||
cros_ec_query_all(ec_dev);
|
||||
mutex_unlock(&ec_dev->lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_register() - Register a new ChromeOS EC, using the provided info.
|
||||
* @ec_dev: Device to register.
|
||||
|
@ -237,6 +255,18 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
|||
dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
|
||||
err);
|
||||
|
||||
if (ec_dev->mkbp_event_supported) {
|
||||
/*
|
||||
* Register the notifier for EC_HOST_EVENT_INTERFACE_READY
|
||||
* event.
|
||||
*/
|
||||
ec_dev->notifier_ready.notifier_call = cros_ec_ready_event;
|
||||
err = blocking_notifier_chain_register(&ec_dev->event_notifier,
|
||||
&ec_dev->notifier_ready);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -48,7 +48,7 @@ struct ec_event {
|
|||
struct list_head node;
|
||||
size_t size;
|
||||
u8 event_type;
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
|
||||
|
@ -301,7 +301,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
|
|||
}
|
||||
|
||||
s_cmd->command += ec->cmd_offset;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, s_cmd);
|
||||
/* Only copy data to userland if data was received. */
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
|
|
@ -116,7 +116,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec,
|
|||
|
||||
param = (struct ec_params_lightbar *)msg->data;
|
||||
param->cmd = LIGHTBAR_CMD_VERSION;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
ret = 0;
|
||||
goto exit;
|
||||
|
@ -193,15 +193,10 @@ static ssize_t brightness_store(struct device *dev,
|
|||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(msg);
|
||||
|
@ -258,13 +253,10 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (msg->result != EC_RES_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
i = 0;
|
||||
ok = 1;
|
||||
}
|
||||
|
@ -305,14 +297,13 @@ static ssize_t sequence_show(struct device *dev,
|
|||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret == -EPROTO) {
|
||||
ret = scnprintf(buf, PAGE_SIZE,
|
||||
"ERROR: EC returned %d\n", msg->result);
|
||||
goto exit;
|
||||
} else if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
resp = (struct ec_response_lightbar *)msg->data;
|
||||
|
@ -344,13 +335,10 @@ static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
kfree(msg);
|
||||
|
@ -377,13 +365,10 @@ static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
kfree(msg);
|
||||
|
@ -425,15 +410,10 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
|
|||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(msg);
|
||||
|
@ -487,13 +467,9 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr,
|
|||
*/
|
||||
msg->outsize = count + extra_bytes;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
exit:
|
||||
|
|
|
@ -553,7 +553,10 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer);
|
|||
* replied with success status. It's not necessary to check msg->result when
|
||||
* using this function.
|
||||
*
|
||||
* Return: The number of bytes transferred on success or negative error code.
|
||||
* Return:
|
||||
* >=0 - The number of bytes transferred
|
||||
* -ENOTSUPP - Operation not supported
|
||||
* -EPROTO - Protocol error
|
||||
*/
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
|
@ -563,6 +566,10 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
|||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
|
||||
} else if (msg->result == EC_RES_INVALID_VERSION) {
|
||||
dev_dbg(ec_dev->dev, "Command invalid version (err:%d)\n",
|
||||
msg->result);
|
||||
return -ENOTSUPP;
|
||||
} else if (msg->result != EC_RES_SUCCESS) {
|
||||
dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
|
||||
return -EPROTO;
|
||||
|
|
|
@ -44,6 +44,8 @@ struct cros_ec_rpmsg {
|
|||
struct completion xfer_ack;
|
||||
struct work_struct host_event_work;
|
||||
struct rpmsg_endpoint *ept;
|
||||
bool has_pending_host_event;
|
||||
bool probe_done;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -177,7 +179,14 @@ static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
|
|||
memcpy(ec_dev->din, resp->data, len);
|
||||
complete(&ec_rpmsg->xfer_ack);
|
||||
} else if (resp->type == HOST_EVENT_MARK) {
|
||||
schedule_work(&ec_rpmsg->host_event_work);
|
||||
/*
|
||||
* If the host event is sent before cros_ec_register is
|
||||
* finished, queue the host event.
|
||||
*/
|
||||
if (ec_rpmsg->probe_done)
|
||||
schedule_work(&ec_rpmsg->host_event_work);
|
||||
else
|
||||
ec_rpmsg->has_pending_host_event = true;
|
||||
} else {
|
||||
dev_warn(ec_dev->dev, "rpmsg received invalid type = %d",
|
||||
resp->type);
|
||||
|
@ -240,6 +249,11 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ec_rpmsg->probe_done = true;
|
||||
|
||||
if (ec_rpmsg->has_pending_host_event)
|
||||
schedule_work(&ec_rpmsg->host_event_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,10 +50,8 @@ static int cros_ec_sensorhub_register(struct device *dev,
|
|||
struct cros_ec_sensorhub *sensorhub)
|
||||
{
|
||||
int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
|
||||
struct cros_ec_command *msg = sensorhub->msg;
|
||||
struct cros_ec_dev *ec = sensorhub->ec;
|
||||
struct ec_params_motion_sense *params;
|
||||
struct ec_response_motion_sense *resp;
|
||||
struct cros_ec_command *msg;
|
||||
int ret, i, sensor_num;
|
||||
char *name;
|
||||
|
||||
|
@ -65,27 +63,19 @@ static int cros_ec_sensorhub_register(struct device *dev,
|
|||
return sensor_num;
|
||||
}
|
||||
|
||||
sensorhub->sensor_num = sensor_num;
|
||||
if (sensor_num == 0) {
|
||||
dev_err(dev, "Zero sensors reported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Prepare a message to send INFO command to each sensor. */
|
||||
msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
|
||||
GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = 1;
|
||||
msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
|
||||
msg->outsize = sizeof(*params);
|
||||
msg->insize = sizeof(*resp);
|
||||
params = (struct ec_params_motion_sense *)msg->data;
|
||||
resp = (struct ec_response_motion_sense *)msg->data;
|
||||
msg->insize = sizeof(struct ec_response_motion_sense);
|
||||
msg->outsize = sizeof(struct ec_params_motion_sense);
|
||||
|
||||
for (i = 0; i < sensor_num; i++) {
|
||||
params->cmd = MOTIONSENSE_CMD_INFO;
|
||||
params->info.sensor_num = i;
|
||||
sensorhub->params->cmd = MOTIONSENSE_CMD_INFO;
|
||||
sensorhub->params->info.sensor_num = i;
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
|
@ -94,7 +84,7 @@ static int cros_ec_sensorhub_register(struct device *dev,
|
|||
continue;
|
||||
}
|
||||
|
||||
switch (resp->info.type) {
|
||||
switch (sensorhub->resp->info.type) {
|
||||
case MOTIONSENSE_TYPE_ACCEL:
|
||||
name = "cros-ec-accel";
|
||||
break;
|
||||
|
@ -117,15 +107,16 @@ static int cros_ec_sensorhub_register(struct device *dev,
|
|||
name = "cros-ec-activity";
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "unknown type %d\n", resp->info.type);
|
||||
dev_warn(dev, "unknown type %d\n",
|
||||
sensorhub->resp->info.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
|
||||
if (ret)
|
||||
goto error;
|
||||
return ret;
|
||||
|
||||
sensor_type[resp->info.type]++;
|
||||
sensor_type[sensorhub->resp->info.type]++;
|
||||
}
|
||||
|
||||
if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
|
||||
|
@ -137,29 +128,41 @@ static int cros_ec_sensorhub_register(struct device *dev,
|
|||
"cros-ec-lid-angle",
|
||||
0);
|
||||
if (ret)
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_sensorhub_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
|
||||
struct cros_ec_sensorhub *data;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
msg = devm_kzalloc(dev, sizeof(struct cros_ec_command) +
|
||||
max((u16)sizeof(struct ec_params_motion_sense),
|
||||
ec->ec_dev->max_response), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->ec = dev_get_drvdata(dev->parent);
|
||||
mutex_init(&data->cmd_lock);
|
||||
|
||||
data->dev = dev;
|
||||
data->ec = ec;
|
||||
data->msg = msg;
|
||||
data->params = (struct ec_params_motion_sense *)msg->data;
|
||||
data->resp = (struct ec_response_motion_sense *)msg->data;
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
/* Check whether this EC is a sensor hub. */
|
||||
|
@ -172,7 +175,8 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev)
|
|||
* If the device has sensors but does not claim to
|
||||
* be a sensor hub, we are in legacy mode.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->sensor_num = 2;
|
||||
for (i = 0; i < data->sensor_num; i++) {
|
||||
ret = cros_ec_sensorhub_allocate_sensor(dev,
|
||||
"cros-ec-accel-legacy", i);
|
||||
if (ret)
|
||||
|
@ -180,12 +184,63 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the EC does not have a FIFO, the sensors will query their data
|
||||
* themselves via sysfs or a software trigger.
|
||||
*/
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
|
||||
ret = cros_ec_sensorhub_ring_add(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* The msg and its data is not under the control of the ring
|
||||
* handler.
|
||||
*/
|
||||
return devm_add_action_or_reset(dev,
|
||||
cros_ec_sensorhub_ring_remove,
|
||||
data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* When the EC is suspending, we must stop sending interrupt,
|
||||
* we may use the same interrupt line for waking up the device.
|
||||
* Tell the EC to stop sending non-interrupt event on the iio ring.
|
||||
*/
|
||||
static int cros_ec_sensorhub_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev);
|
||||
struct cros_ec_dev *ec = sensorhub->ec;
|
||||
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
|
||||
return cros_ec_sensorhub_ring_fifo_enable(sensorhub, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_sensorhub_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev);
|
||||
struct cros_ec_dev *ec = sensorhub->ec;
|
||||
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
|
||||
return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cros_ec_sensorhub_pm_ops,
|
||||
cros_ec_sensorhub_suspend,
|
||||
cros_ec_sensorhub_resume);
|
||||
|
||||
static struct platform_driver cros_ec_sensorhub_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = &cros_ec_sensorhub_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_sensorhub_probe,
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -127,7 +127,8 @@ static int terminate_request(struct cros_ec_device *ec_dev)
|
|||
*/
|
||||
spi_message_init(&msg);
|
||||
memset(&trans, 0, sizeof(trans));
|
||||
trans.delay_usecs = ec_spi->end_of_msg_delay;
|
||||
trans.delay.value = ec_spi->end_of_msg_delay;
|
||||
trans.delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
spi_message_add_tail(&trans, &msg);
|
||||
|
||||
ret = spi_sync_locked(ec_spi->spi, &msg);
|
||||
|
@ -416,7 +417,8 @@ static int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
|||
spi_message_init(&msg);
|
||||
if (ec_spi->start_of_msg_delay) {
|
||||
memset(&trans_delay, 0, sizeof(trans_delay));
|
||||
trans_delay.delay_usecs = ec_spi->start_of_msg_delay;
|
||||
trans_delay.delay.value = ec_spi->start_of_msg_delay;
|
||||
trans_delay.delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
spi_message_add_tail(&trans_delay, &msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,14 +149,14 @@ static ssize_t version_show(struct device *dev,
|
|||
/* Get build info. */
|
||||
msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset;
|
||||
msg->insize = EC_HOST_PARAM_SIZE;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Build info: XFER ERROR %d\n", ret);
|
||||
else if (msg->result != EC_RES_SUCCESS)
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret == -EPROTO) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Build info: EC error %d\n", msg->result);
|
||||
else {
|
||||
} else if (ret < 0) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Build info: XFER ERROR %d\n", ret);
|
||||
} else {
|
||||
msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Build info: %s\n", msg->data);
|
||||
|
@ -165,14 +165,14 @@ static ssize_t version_show(struct device *dev,
|
|||
/* Get chip info. */
|
||||
msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset;
|
||||
msg->insize = sizeof(*r_chip);
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Chip info: XFER ERROR %d\n", ret);
|
||||
else if (msg->result != EC_RES_SUCCESS)
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret == -EPROTO) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Chip info: EC error %d\n", msg->result);
|
||||
else {
|
||||
} else if (ret < 0) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Chip info: XFER ERROR %d\n", ret);
|
||||
} else {
|
||||
r_chip = (struct ec_response_get_chip_info *)msg->data;
|
||||
|
||||
r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0';
|
||||
|
@ -189,14 +189,14 @@ static ssize_t version_show(struct device *dev,
|
|||
/* Get board version */
|
||||
msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset;
|
||||
msg->insize = sizeof(*r_board);
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Board version: XFER ERROR %d\n", ret);
|
||||
else if (msg->result != EC_RES_SUCCESS)
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret == -EPROTO) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Board version: EC error %d\n", msg->result);
|
||||
else {
|
||||
} else if (ret < 0) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"Board version: XFER ERROR %d\n", ret);
|
||||
} else {
|
||||
r_board = (struct ec_response_board_version *)msg->data;
|
||||
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* This driver provides the ability to view and manage Type C ports through the
|
||||
* Chrome OS EC.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/typec.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-typec"
|
||||
|
||||
/* Platform-specific data for the Chrome OS EC Type C controller. */
|
||||
struct cros_typec_data {
|
||||
struct device *dev;
|
||||
struct cros_ec_device *ec;
|
||||
int num_ports;
|
||||
unsigned int cmd_ver;
|
||||
/* Array of ports, indexed by port number. */
|
||||
struct typec_port *ports[EC_USB_PD_MAX_PORTS];
|
||||
/* Initial capabilities for each port. */
|
||||
struct typec_capability *caps[EC_USB_PD_MAX_PORTS];
|
||||
};
|
||||
|
||||
static int cros_typec_parse_port_props(struct typec_capability *cap,
|
||||
struct fwnode_handle *fwnode,
|
||||
struct device *dev)
|
||||
{
|
||||
const char *buf;
|
||||
int ret;
|
||||
|
||||
memset(cap, 0, sizeof(*cap));
|
||||
ret = fwnode_property_read_string(fwnode, "power-role", &buf);
|
||||
if (ret) {
|
||||
dev_err(dev, "power-role not found: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = typec_find_port_power_role(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cap->type = ret;
|
||||
|
||||
ret = fwnode_property_read_string(fwnode, "data-role", &buf);
|
||||
if (ret) {
|
||||
dev_err(dev, "data-role not found: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = typec_find_port_data_role(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cap->data = ret;
|
||||
|
||||
ret = fwnode_property_read_string(fwnode, "try-power-role", &buf);
|
||||
if (ret) {
|
||||
dev_err(dev, "try-power-role not found: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = typec_find_power_role(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cap->prefer_role = ret;
|
||||
|
||||
cap->fwnode = fwnode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_typec_init_ports(struct cros_typec_data *typec)
|
||||
{
|
||||
struct device *dev = typec->dev;
|
||||
struct typec_capability *cap;
|
||||
struct fwnode_handle *fwnode;
|
||||
const char *port_prop;
|
||||
int ret;
|
||||
int i;
|
||||
int nports;
|
||||
u32 port_num = 0;
|
||||
|
||||
nports = device_get_child_node_count(dev);
|
||||
if (nports == 0) {
|
||||
dev_err(dev, "No port entries found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (nports > typec->num_ports) {
|
||||
dev_err(dev, "More ports listed than can be supported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* DT uses "reg" to specify port number. */
|
||||
port_prop = dev->of_node ? "reg" : "port-number";
|
||||
device_for_each_child_node(dev, fwnode) {
|
||||
if (fwnode_property_read_u32(fwnode, port_prop, &port_num)) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "No port-number for port, aborting.\n");
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
if (port_num >= typec->num_ports) {
|
||||
dev_err(dev, "Invalid port number.\n");
|
||||
ret = -EINVAL;
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Registering port %d\n", port_num);
|
||||
|
||||
cap = devm_kzalloc(dev, sizeof(*cap), GFP_KERNEL);
|
||||
if (!cap) {
|
||||
ret = -ENOMEM;
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
typec->caps[port_num] = cap;
|
||||
|
||||
ret = cros_typec_parse_port_props(cap, fwnode, dev);
|
||||
if (ret < 0)
|
||||
goto unregister_ports;
|
||||
|
||||
typec->ports[port_num] = typec_register_port(dev, cap);
|
||||
if (IS_ERR(typec->ports[port_num])) {
|
||||
dev_err(dev, "Failed to register port %d\n", port_num);
|
||||
ret = PTR_ERR(typec->ports[port_num]);
|
||||
goto unregister_ports;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_ports:
|
||||
for (i = 0; i < typec->num_ports; i++)
|
||||
typec_unregister_port(typec->ports[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_typec_ec_command(struct cros_typec_data *typec,
|
||||
unsigned int version,
|
||||
unsigned int command,
|
||||
void *outdata,
|
||||
unsigned int outsize,
|
||||
void *indata,
|
||||
unsigned int insize)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = version;
|
||||
msg->command = command;
|
||||
msg->outsize = outsize;
|
||||
msg->insize = insize;
|
||||
|
||||
if (outsize)
|
||||
memcpy(msg->data, outdata, outsize);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(typec->ec, msg);
|
||||
if (ret >= 0 && insize)
|
||||
memcpy(indata, msg->data, insize);
|
||||
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cros_typec_set_port_params_v0(struct cros_typec_data *typec,
|
||||
int port_num, struct ec_response_usb_pd_control *resp)
|
||||
{
|
||||
struct typec_port *port = typec->ports[port_num];
|
||||
enum typec_orientation polarity;
|
||||
|
||||
if (!resp->enabled)
|
||||
polarity = TYPEC_ORIENTATION_NONE;
|
||||
else if (!resp->polarity)
|
||||
polarity = TYPEC_ORIENTATION_NORMAL;
|
||||
else
|
||||
polarity = TYPEC_ORIENTATION_REVERSE;
|
||||
|
||||
typec_set_pwr_role(port, resp->role ? TYPEC_SOURCE : TYPEC_SINK);
|
||||
typec_set_orientation(port, polarity);
|
||||
}
|
||||
|
||||
static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
|
||||
int port_num, struct ec_response_usb_pd_control_v1 *resp)
|
||||
{
|
||||
struct typec_port *port = typec->ports[port_num];
|
||||
enum typec_orientation polarity;
|
||||
|
||||
if (!(resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED))
|
||||
polarity = TYPEC_ORIENTATION_NONE;
|
||||
else if (!resp->polarity)
|
||||
polarity = TYPEC_ORIENTATION_NORMAL;
|
||||
else
|
||||
polarity = TYPEC_ORIENTATION_REVERSE;
|
||||
typec_set_orientation(port, polarity);
|
||||
typec_set_data_role(port, resp->role & PD_CTRL_RESP_ROLE_DATA ?
|
||||
TYPEC_HOST : TYPEC_DEVICE);
|
||||
typec_set_pwr_role(port, resp->role & PD_CTRL_RESP_ROLE_POWER ?
|
||||
TYPEC_SOURCE : TYPEC_SINK);
|
||||
typec_set_vconn_role(port, resp->role & PD_CTRL_RESP_ROLE_VCONN ?
|
||||
TYPEC_SOURCE : TYPEC_SINK);
|
||||
}
|
||||
|
||||
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
|
||||
{
|
||||
struct ec_params_usb_pd_control req;
|
||||
struct ec_response_usb_pd_control_v1 resp;
|
||||
int ret;
|
||||
|
||||
if (port_num < 0 || port_num >= typec->num_ports) {
|
||||
dev_err(typec->dev, "cannot get status for invalid port %d\n",
|
||||
port_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
req.port = port_num;
|
||||
req.role = USB_PD_CTRL_ROLE_NO_CHANGE;
|
||||
req.mux = USB_PD_CTRL_MUX_NO_CHANGE;
|
||||
req.swap = USB_PD_CTRL_SWAP_NONE;
|
||||
|
||||
ret = cros_typec_ec_command(typec, typec->cmd_ver,
|
||||
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(typec->dev, "Enabled %d: 0x%hhx\n", port_num, resp.enabled);
|
||||
dev_dbg(typec->dev, "Role %d: 0x%hhx\n", port_num, resp.role);
|
||||
dev_dbg(typec->dev, "Polarity %d: 0x%hhx\n", port_num, resp.polarity);
|
||||
dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state);
|
||||
|
||||
if (typec->cmd_ver == 1)
|
||||
cros_typec_set_port_params_v1(typec, port_num, &resp);
|
||||
else
|
||||
cros_typec_set_port_params_v0(typec, port_num,
|
||||
(struct ec_response_usb_pd_control *) &resp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
|
||||
{
|
||||
struct ec_params_get_cmd_versions_v1 req_v1;
|
||||
struct ec_response_get_cmd_versions resp;
|
||||
int ret;
|
||||
|
||||
/* We're interested in the PD control command version. */
|
||||
req_v1.cmd = EC_CMD_USB_PD_CONTROL;
|
||||
ret = cros_typec_ec_command(typec, 1, EC_CMD_GET_CMD_VERSIONS,
|
||||
&req_v1, sizeof(req_v1), &resp,
|
||||
sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (resp.version_mask & EC_VER_MASK(1))
|
||||
typec->cmd_ver = 1;
|
||||
else
|
||||
typec->cmd_ver = 0;
|
||||
|
||||
dev_dbg(typec->dev, "PD Control has version mask 0x%hhx\n",
|
||||
typec->cmd_ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id cros_typec_acpi_id[] = {
|
||||
{ "GOOG0014", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cros_typec_acpi_id);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cros_typec_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-typec", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cros_typec_of_match);
|
||||
#endif
|
||||
|
||||
static int cros_typec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_typec_data *typec;
|
||||
struct ec_response_usb_pd_ports resp;
|
||||
int ret, i;
|
||||
|
||||
typec = devm_kzalloc(dev, sizeof(*typec), GFP_KERNEL);
|
||||
if (!typec)
|
||||
return -ENOMEM;
|
||||
|
||||
typec->dev = dev;
|
||||
typec->ec = dev_get_drvdata(pdev->dev.parent);
|
||||
platform_set_drvdata(pdev, typec);
|
||||
|
||||
ret = cros_typec_get_cmd_version(typec);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get PD command version info\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
|
||||
&resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
typec->num_ports = resp.num_ports;
|
||||
if (typec->num_ports > EC_USB_PD_MAX_PORTS) {
|
||||
dev_warn(typec->dev,
|
||||
"Too many ports reported: %d, limiting to max: %d\n",
|
||||
typec->num_ports, EC_USB_PD_MAX_PORTS);
|
||||
typec->num_ports = EC_USB_PD_MAX_PORTS;
|
||||
}
|
||||
|
||||
ret = cros_typec_init_ports(typec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < typec->num_ports; i++) {
|
||||
ret = cros_typec_port_update(typec, i);
|
||||
if (ret < 0)
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_ports:
|
||||
for (i = 0; i < typec->num_ports; i++)
|
||||
if (typec->ports[i])
|
||||
typec_unregister_port(typec->ports[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver cros_typec_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.acpi_match_table = ACPI_PTR(cros_typec_acpi_id),
|
||||
.of_match_table = of_match_ptr(cros_typec_of_match),
|
||||
},
|
||||
.probe = cros_typec_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(cros_typec_driver);
|
||||
|
||||
MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>");
|
||||
MODULE_DESCRIPTION("Chrome OS EC Type C control");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -40,7 +40,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
|
|||
msg->outsize = para_sz;
|
||||
msg->insize = resp_sz;
|
||||
|
||||
err = cros_ec_cmd_xfer(ecdev, msg);
|
||||
err = cros_ec_cmd_xfer_status(ecdev, msg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Error sending read request: %d\n", err);
|
||||
kfree(msg);
|
||||
|
@ -83,7 +83,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
|
|||
msg->outsize = para_sz;
|
||||
msg->insize = 0;
|
||||
|
||||
err = cros_ec_cmd_xfer(ecdev, msg);
|
||||
err = cros_ec_cmd_xfer_status(ecdev, msg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Error sending write request: %d\n", err);
|
||||
kfree(msg);
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* This driver serves as the receiver of cros_ec PD host events.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_data/cros_usbpd_notify.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRV_NAME "cros-usbpd-notify"
|
||||
#define DRV_NAME_PLAT_ACPI "cros-usbpd-notify-acpi"
|
||||
#define ACPI_DRV_NAME "GOOG0003"
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(cros_usbpd_notifier_list);
|
||||
|
||||
struct cros_usbpd_notify_data {
|
||||
struct device *dev;
|
||||
struct cros_ec_device *ec;
|
||||
struct notifier_block nb;
|
||||
};
|
||||
|
||||
/**
|
||||
* cros_usbpd_register_notify - Register a notifier callback for PD events.
|
||||
* @nb: Notifier block pointer to register
|
||||
*
|
||||
* On ACPI platforms this corresponds to host events on the ECPD
|
||||
* "GOOG0003" ACPI device. On non-ACPI platforms this will filter mkbp events
|
||||
* for USB PD events.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_usbpd_register_notify(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&cros_usbpd_notifier_list,
|
||||
nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cros_usbpd_register_notify);
|
||||
|
||||
/**
|
||||
* cros_usbpd_unregister_notify - Unregister notifier callback for PD events.
|
||||
* @nb: Notifier block pointer to unregister
|
||||
*
|
||||
* Unregister a notifier callback that was previously registered with
|
||||
* cros_usbpd_register_notify().
|
||||
*/
|
||||
void cros_usbpd_unregister_notify(struct notifier_block *nb)
|
||||
{
|
||||
blocking_notifier_chain_unregister(&cros_usbpd_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify);
|
||||
|
||||
/**
|
||||
* cros_ec_pd_command - Send a command to the EC.
|
||||
*
|
||||
* @ec_dev: EC device
|
||||
* @command: EC command
|
||||
* @outdata: EC command output data
|
||||
* @outsize: Size of outdata
|
||||
* @indata: EC command input data
|
||||
* @insize: Size of indata
|
||||
*
|
||||
* Return: >= 0 on success, negative error number on failure.
|
||||
*/
|
||||
static int cros_ec_pd_command(struct cros_ec_device *ec_dev,
|
||||
int command,
|
||||
uint8_t *outdata,
|
||||
int outsize,
|
||||
uint8_t *indata,
|
||||
int insize)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max(insize, outsize), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = command;
|
||||
msg->outsize = outsize;
|
||||
msg->insize = insize;
|
||||
|
||||
if (outsize)
|
||||
memcpy(msg->data, outdata, outsize);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (insize)
|
||||
memcpy(indata, msg->data, insize);
|
||||
error:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cros_usbpd_get_event_and_notify(struct device *dev,
|
||||
struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct ec_response_host_event_status host_event_status;
|
||||
u32 event = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We still send a 0 event out to older devices which don't
|
||||
* have the updated device heirarchy.
|
||||
*/
|
||||
if (!ec_dev) {
|
||||
dev_dbg(dev,
|
||||
"EC device inaccessible; sending 0 event status.\n");
|
||||
goto send_notify;
|
||||
}
|
||||
|
||||
/* Check for PD host events on EC. */
|
||||
ret = cros_ec_pd_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS,
|
||||
NULL, 0,
|
||||
(uint8_t *)&host_event_status,
|
||||
sizeof(host_event_status));
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Can't get host event status (err: %d)\n", ret);
|
||||
goto send_notify;
|
||||
}
|
||||
|
||||
event = host_event_status.status;
|
||||
|
||||
send_notify:
|
||||
blocking_notifier_call_chain(&cros_usbpd_notifier_list, event, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
static void cros_usbpd_notify_acpi(acpi_handle device, u32 event, void *data)
|
||||
{
|
||||
struct cros_usbpd_notify_data *pdnotify = data;
|
||||
|
||||
cros_usbpd_get_event_and_notify(pdnotify->dev, pdnotify->ec);
|
||||
}
|
||||
|
||||
static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_usbpd_notify_data *pdnotify;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acpi_device *adev;
|
||||
struct cros_ec_device *ec_dev;
|
||||
acpi_status status;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
|
||||
pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL);
|
||||
if (!pdnotify)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get the EC device pointer needed to talk to the EC. */
|
||||
ec_dev = dev_get_drvdata(dev->parent);
|
||||
if (!ec_dev) {
|
||||
/*
|
||||
* We continue even for older devices which don't have the
|
||||
* correct device heirarchy, namely, GOOG0003 is a child
|
||||
* of GOOG0004.
|
||||
*/
|
||||
dev_warn(dev, "Couldn't get Chrome EC device pointer.\n");
|
||||
}
|
||||
|
||||
pdnotify->dev = dev;
|
||||
pdnotify->ec = ec_dev;
|
||||
|
||||
status = acpi_install_notify_handler(adev->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
cros_usbpd_notify_acpi,
|
||||
pdnotify);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_warn(dev, "Failed to register notify handler %08x\n",
|
||||
status);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_usbpd_notify_remove_acpi(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
|
||||
cros_usbpd_notify_acpi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = {
|
||||
{ ACPI_DRV_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cros_usbpd_notify_acpi_device_ids);
|
||||
|
||||
static struct platform_driver cros_usbpd_notify_acpi_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME_PLAT_ACPI,
|
||||
.acpi_match_table = cros_usbpd_notify_acpi_device_ids,
|
||||
},
|
||||
.probe = cros_usbpd_notify_probe_acpi,
|
||||
.remove = cros_usbpd_notify_remove_acpi,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int cros_usbpd_notify_plat(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend,
|
||||
void *data)
|
||||
{
|
||||
struct cros_usbpd_notify_data *pdnotify = container_of(nb,
|
||||
struct cros_usbpd_notify_data, nb);
|
||||
struct cros_ec_device *ec_dev = (struct cros_ec_device *)data;
|
||||
u32 host_event = cros_ec_get_host_event(ec_dev);
|
||||
|
||||
if (!host_event)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) {
|
||||
cros_usbpd_get_event_and_notify(pdnotify->dev, ec_dev);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int cros_usbpd_notify_probe_plat(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent);
|
||||
struct cros_usbpd_notify_data *pdnotify;
|
||||
int ret;
|
||||
|
||||
pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL);
|
||||
if (!pdnotify)
|
||||
return -ENOMEM;
|
||||
|
||||
pdnotify->dev = dev;
|
||||
pdnotify->ec = ecdev->ec_dev;
|
||||
pdnotify->nb.notifier_call = cros_usbpd_notify_plat;
|
||||
|
||||
dev_set_drvdata(dev, pdnotify);
|
||||
|
||||
ret = blocking_notifier_chain_register(&ecdev->ec_dev->event_notifier,
|
||||
&pdnotify->nb);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to register notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_usbpd_notify_remove_plat(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent);
|
||||
struct cros_usbpd_notify_data *pdnotify =
|
||||
(struct cros_usbpd_notify_data *)dev_get_drvdata(dev);
|
||||
|
||||
blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier,
|
||||
&pdnotify->nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cros_usbpd_notify_plat_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = cros_usbpd_notify_probe_plat,
|
||||
.remove = cros_usbpd_notify_remove_plat,
|
||||
};
|
||||
|
||||
static int __init cros_usbpd_notify_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&cros_usbpd_notify_plat_driver);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
platform_driver_register(&cros_usbpd_notify_acpi_driver);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cros_usbpd_notify_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_ACPI
|
||||
platform_driver_unregister(&cros_usbpd_notify_acpi_driver);
|
||||
#endif
|
||||
platform_driver_unregister(&cros_usbpd_notify_plat_driver);
|
||||
}
|
||||
|
||||
module_init(cros_usbpd_notify_init);
|
||||
module_exit(cros_usbpd_notify_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ChromeOS power delivery notifier device");
|
||||
MODULE_AUTHOR("Jon Flatley <jflat@chromium.org>");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
|
@ -79,7 +79,7 @@ static DEFINE_IDA(event_ida);
|
|||
struct ec_event {
|
||||
u16 size;
|
||||
u16 type;
|
||||
u16 event[0];
|
||||
u16 event[];
|
||||
} __packed;
|
||||
|
||||
#define ec_event_num_words(ev) (ev->size - 1)
|
||||
|
@ -96,7 +96,7 @@ struct ec_event_queue {
|
|||
int capacity;
|
||||
int head;
|
||||
int tail;
|
||||
struct ec_event *entries[0];
|
||||
struct ec_event *entries[];
|
||||
};
|
||||
|
||||
/* Maximum number of events to store in ec_event_queue */
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/platform_data/wilco-ec.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/* Operation code; what the EC should do with the property */
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
* See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_data/wilco-ec.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define CMD_KB_CMOS 0x7C
|
||||
#define SUB_CMD_KB_CMOS_AUTO_ON 0x03
|
||||
|
|
|
@ -659,7 +659,7 @@ config CHARGER_RT9455
|
|||
|
||||
config CHARGER_CROS_USBPD
|
||||
tristate "ChromeOS EC based USBPD charger"
|
||||
depends on CROS_EC
|
||||
depends on CROS_USBPD_NOTIFY
|
||||
default n
|
||||
help
|
||||
Say Y here to enable ChromeOS EC based USBPD charger
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_data/cros_usbpd_notify.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -517,32 +518,21 @@ static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy,
|
|||
}
|
||||
|
||||
static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend,
|
||||
unsigned long host_event,
|
||||
void *_notify)
|
||||
{
|
||||
struct cros_ec_device *ec_device;
|
||||
struct charger_data *charger;
|
||||
u32 host_event;
|
||||
struct charger_data *charger = container_of(nb, struct charger_data,
|
||||
notifier);
|
||||
|
||||
charger = container_of(nb, struct charger_data, notifier);
|
||||
ec_device = charger->ec_device;
|
||||
|
||||
host_event = cros_ec_get_host_event(ec_device);
|
||||
if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) {
|
||||
cros_usbpd_charger_power_changed(charger->ports[0]->psy);
|
||||
return NOTIFY_OK;
|
||||
} else {
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
cros_usbpd_charger_power_changed(charger->ports[0]->psy);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void cros_usbpd_charger_unregister_notifier(void *data)
|
||||
{
|
||||
struct charger_data *charger = data;
|
||||
struct cros_ec_device *ec_device = charger->ec_device;
|
||||
|
||||
blocking_notifier_chain_unregister(&ec_device->event_notifier,
|
||||
&charger->notifier);
|
||||
cros_usbpd_unregister_notify(&charger->notifier);
|
||||
}
|
||||
|
||||
static int cros_usbpd_charger_probe(struct platform_device *pd)
|
||||
|
@ -676,21 +666,17 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (ec_device->mkbp_event_supported) {
|
||||
/* Get PD events from the EC */
|
||||
charger->notifier.notifier_call = cros_usbpd_charger_ec_event;
|
||||
ret = blocking_notifier_chain_register(
|
||||
&ec_device->event_notifier,
|
||||
&charger->notifier);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "failed to register notifier\n");
|
||||
} else {
|
||||
ret = devm_add_action_or_reset(dev,
|
||||
cros_usbpd_charger_unregister_notifier,
|
||||
charger);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
/* Get PD events from the EC */
|
||||
charger->notifier.notifier_call = cros_usbpd_charger_ec_event;
|
||||
ret = cros_usbpd_register_notify(&charger->notifier);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "failed to register notifier\n");
|
||||
} else {
|
||||
ret = devm_add_action_or_reset(dev,
|
||||
cros_usbpd_charger_unregister_notifier,
|
||||
charger);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/irqreturn.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_data/cros_ec_sensorhub.h>
|
||||
|
||||
enum {
|
||||
CROS_EC_SENSOR_X,
|
||||
|
@ -29,8 +30,7 @@ enum {
|
|||
*/
|
||||
#define CROS_EC_SAMPLE_SIZE (sizeof(s64) * 2)
|
||||
|
||||
/* Minimum sampling period to use when device is suspending */
|
||||
#define CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY 1000 /* 1 second */
|
||||
typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p);
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensors_core_state - state data for EC sensors IIO driver
|
||||
|
@ -50,7 +50,9 @@ enum {
|
|||
* the timestamp. The timestamp is always last and
|
||||
* is always 8-byte aligned.
|
||||
* @read_ec_sensors_data: function used for accessing sensors values
|
||||
* @cuur_sampl_freq: current sampling period
|
||||
* @fifo_max_event_count: Size of the EC sensor FIFO
|
||||
* @frequencies: Table of known available frequencies:
|
||||
* 0, Min and Max in mHz
|
||||
*/
|
||||
struct cros_ec_sensors_core_state {
|
||||
struct cros_ec_device *ec;
|
||||
|
@ -73,101 +75,34 @@ struct cros_ec_sensors_core_state {
|
|||
int (*read_ec_sensors_data)(struct iio_dev *indio_dev,
|
||||
unsigned long scan_mask, s16 *data);
|
||||
|
||||
int curr_sampl_freq;
|
||||
|
||||
/* Table of known available frequencies : 0, Min and Max in mHz */
|
||||
int frequencies[3];
|
||||
u32 fifo_max_event_count;
|
||||
int frequencies[6];
|
||||
};
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_read_lpc() - retrieve data from EC shared memory
|
||||
* @indio_dev: pointer to IIO device
|
||||
* @scan_mask: bitmap of the sensor indices to scan
|
||||
* @data: location to store data
|
||||
*
|
||||
* This is the safe function for reading the EC data. It guarantees that the
|
||||
* data sampled was not modified by the EC while being read.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask,
|
||||
s16 *data);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol
|
||||
* @indio_dev: pointer to IIO device
|
||||
* @scan_mask: bitmap of the sensor indices to scan
|
||||
* @data: location to store data
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask,
|
||||
s16 *data);
|
||||
|
||||
struct platform_device;
|
||||
/**
|
||||
* cros_ec_sensors_core_init() - basic initialization of the core structure
|
||||
* @pdev: platform device created for the sensors
|
||||
* @indio_dev: iio device structure of the device
|
||||
* @physical_device: true if the device refers to a physical device
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_core_init(struct platform_device *pdev,
|
||||
struct iio_dev *indio_dev, bool physical_device);
|
||||
struct iio_dev *indio_dev, bool physical_device,
|
||||
cros_ec_sensors_capture_t trigger_capture,
|
||||
cros_ec_sensorhub_push_data_cb_t push_data);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_capture() - the trigger handler function
|
||||
* @irq: the interrupt number.
|
||||
* @p: a pointer to the poll function.
|
||||
*
|
||||
* On a trigger event occurring, if the pollfunc is attached then this
|
||||
* handler is called as a threaded interrupt (and hence may sleep). It
|
||||
* is responsible for grabbing data from the device and pushing it into
|
||||
* the associated buffer.
|
||||
*
|
||||
* Return: IRQ_HANDLED
|
||||
*/
|
||||
irqreturn_t cros_ec_sensors_capture(int irq, void *p);
|
||||
int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
|
||||
s16 *data,
|
||||
s64 timestamp);
|
||||
|
||||
/**
|
||||
* cros_ec_motion_send_host_cmd() - send motion sense host command
|
||||
* @st: pointer to state information for device
|
||||
* @opt_length: optional length to reduce the response size, useful on the data
|
||||
* path. Otherwise, the maximal allowed response size is used
|
||||
*
|
||||
* When called, the sub-command is assumed to be set in param->cmd.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *st,
|
||||
u16 opt_length);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_read() - function to request a value from the sensor
|
||||
* @st: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @val: will contain one element making up the returned value
|
||||
* @val2: will contain another element making up the returned value
|
||||
* @mask: specifies which values to be requested
|
||||
*
|
||||
* Return: the type of value returned by the device
|
||||
*/
|
||||
int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_read_avail() - get available values
|
||||
* @indio_dev: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @vals: list of available values
|
||||
* @type: type of data returned
|
||||
* @length: number of data returned in the array
|
||||
* @mask: specifies which values to be requested
|
||||
*
|
||||
* Return: an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST
|
||||
*/
|
||||
int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals,
|
||||
|
@ -175,23 +110,12 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
|
|||
int *length,
|
||||
long mask);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_core_write() - function to write a value to the sensor
|
||||
* @st: pointer to state information for device
|
||||
* @chan: channel specification structure table
|
||||
* @val: first part of value to write
|
||||
* @val2: second part of value to write
|
||||
* @mask: specifies which values to write
|
||||
*
|
||||
* Return: the type of value returned by the device
|
||||
*/
|
||||
int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask);
|
||||
|
||||
extern const struct dev_pm_ops cros_ec_sensors_pm_ops;
|
||||
|
||||
/* List of extended channel specification for all sensors */
|
||||
extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[];
|
||||
extern const struct attribute *cros_ec_sensor_fifo_attributes[];
|
||||
|
||||
#endif /* __CROS_EC_SENSORS_CORE_H */
|
||||
|
|
|
@ -629,6 +629,8 @@ static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev)
|
|||
return indio_dev->clock_id;
|
||||
}
|
||||
|
||||
int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id);
|
||||
|
||||
/**
|
||||
* dev_to_iio_dev() - Get IIO device struct from a device struct
|
||||
* @dev: The device embedded in the IIO device
|
||||
|
|
|
@ -125,6 +125,9 @@ struct cros_ec_command {
|
|||
* @host_event_wake_mask: Mask of host events that cause wake from suspend.
|
||||
* @last_event_time: exact time from the hard irq when we got notified of
|
||||
* a new event.
|
||||
* @notifier_ready: The notifier_block to let the kernel re-query EC
|
||||
* communication protocol when the EC sends
|
||||
* EC_HOST_EVENT_INTERFACE_READY.
|
||||
* @ec: The platform_device used by the mfd driver to interface with the
|
||||
* main EC.
|
||||
* @pd: The platform_device used by the mfd driver to interface with the
|
||||
|
@ -166,6 +169,7 @@ struct cros_ec_device {
|
|||
u32 host_event_wake_mask;
|
||||
u32 last_resume_result;
|
||||
ktime_t last_event_time;
|
||||
struct notifier_block notifier_ready;
|
||||
|
||||
/* The platform devices used by the mfd driver */
|
||||
struct platform_device *ec;
|
||||
|
|
|
@ -8,8 +8,13 @@
|
|||
#ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
|
||||
#define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
|
||||
struct iio_dev;
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
|
||||
* @sensor_num: Id of the sensor, as reported by the EC.
|
||||
|
@ -19,12 +24,170 @@ struct cros_ec_sensor_platform {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensorhub - Sensor Hub device data.
|
||||
* typedef cros_ec_sensorhub_push_data_cb_t - Callback function to send datum
|
||||
* to specific sensors.
|
||||
*
|
||||
* @ec: Embedded Controller where the hub is located.
|
||||
* @indio_dev: The IIO device that will process the sample.
|
||||
* @data: Vector array of the ring sample.
|
||||
* @timestamp: Timestamp in host timespace when the sample was acquired by
|
||||
* the EC.
|
||||
*/
|
||||
struct cros_ec_sensorhub {
|
||||
struct cros_ec_dev *ec;
|
||||
typedef int (*cros_ec_sensorhub_push_data_cb_t)(struct iio_dev *indio_dev,
|
||||
s16 *data,
|
||||
s64 timestamp);
|
||||
|
||||
struct cros_ec_sensorhub_sensor_push_data {
|
||||
struct iio_dev *indio_dev;
|
||||
cros_ec_sensorhub_push_data_cb_t push_data_cb;
|
||||
};
|
||||
|
||||
enum {
|
||||
CROS_EC_SENSOR_LAST_TS,
|
||||
CROS_EC_SENSOR_NEW_TS,
|
||||
CROS_EC_SENSOR_ALL_TS
|
||||
};
|
||||
|
||||
struct cros_ec_sensors_ring_sample {
|
||||
u8 sensor_id;
|
||||
u8 flag;
|
||||
s16 vector[3];
|
||||
s64 timestamp;
|
||||
} __packed;
|
||||
|
||||
/* State used for cros_ec_ring_fix_overflow */
|
||||
struct cros_ec_sensors_ec_overflow_state {
|
||||
s64 offset;
|
||||
s64 last;
|
||||
};
|
||||
|
||||
/* Length of the filter, how long to remember entries for */
|
||||
#define CROS_EC_SENSORHUB_TS_HISTORY_SIZE 64
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensors_ts_filter_state - Timestamp filetr state.
|
||||
*
|
||||
* @x_offset: x is EC interrupt time. x_offset its last value.
|
||||
* @y_offset: y is the difference between AP and EC time, y_offset its last
|
||||
* value.
|
||||
* @x_history: The past history of x, relative to x_offset.
|
||||
* @y_history: The past history of y, relative to y_offset.
|
||||
* @m_history: rate between y and x.
|
||||
* @history_len: Amount of valid historic data in the arrays.
|
||||
* @temp_buf: Temporary buffer used when updating the filter.
|
||||
* @median_m: median value of m_history
|
||||
* @median_error: final error to apply to AP interrupt timestamp to get the
|
||||
* "true timestamp" the event occurred.
|
||||
*/
|
||||
struct cros_ec_sensors_ts_filter_state {
|
||||
s64 x_offset, y_offset;
|
||||
s64 x_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
|
||||
s64 y_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
|
||||
s64 m_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
|
||||
int history_len;
|
||||
|
||||
s64 temp_buf[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
|
||||
|
||||
s64 median_m;
|
||||
s64 median_error;
|
||||
};
|
||||
|
||||
/* struct cros_ec_sensors_ts_batch_state - State of batch of a single sensor.
|
||||
*
|
||||
* Use to store information to batch data using median fileter information.
|
||||
*
|
||||
* @penul_ts: last but one batch timestamp (penultimate timestamp).
|
||||
* Used for timestamp spreading calculations
|
||||
* when a batch shows up.
|
||||
* @penul_len: last but one batch length.
|
||||
* @last_ts: Last batch timestam.
|
||||
* @last_len: Last batch length.
|
||||
* @newest_sensor_event: Last sensor timestamp.
|
||||
*/
|
||||
struct cros_ec_sensors_ts_batch_state {
|
||||
s64 penul_ts;
|
||||
int penul_len;
|
||||
s64 last_ts;
|
||||
int last_len;
|
||||
s64 newest_sensor_event;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct cros_ec_sensorhub - Sensor Hub device data.
|
||||
*
|
||||
* @dev: Device object, mostly used for logging.
|
||||
* @ec: Embedded Controller where the hub is located.
|
||||
* @sensor_num: Number of MEMS sensors present in the EC.
|
||||
* @msg: Structure to send FIFO requests.
|
||||
* @params: Pointer to parameters in msg.
|
||||
* @resp: Pointer to responses in msg.
|
||||
* @cmd_lock : Lock for sending msg.
|
||||
* @notifier: Notifier to kick the FIFO interrupt.
|
||||
* @ring: Preprocessed ring to store events.
|
||||
* @fifo_timestamp: Array for event timestamp and spreading.
|
||||
* @fifo_info: Copy of FIFO information coming from the EC.
|
||||
* @fifo_size: Size of the ring.
|
||||
* @batch_state: Per sensor information of the last batches received.
|
||||
* @overflow_a: For handling timestamp overflow for a time (sensor events)
|
||||
* @overflow_b: For handling timestamp overflow for b time (ec interrupts)
|
||||
* @filter: Medium fileter structure.
|
||||
* @tight_timestamps: Set to truen when EC support tight timestamping:
|
||||
* The timestamps reported from the EC have low jitter.
|
||||
* Timestamps also come before every sample. Set either
|
||||
* by feature bits coming from the EC or userspace.
|
||||
* @future_timestamp_count: Statistics used to compute shaved time.
|
||||
* This occurs when timestamp interpolation from EC
|
||||
* time to AP time accidentally puts timestamps in
|
||||
* the future. These timestamps are clamped to
|
||||
* `now` and these count/total_ns maintain the
|
||||
* statistics for how much time was removed in a
|
||||
* given period.
|
||||
* @future_timestamp_total_ns: Total amount of time shaved.
|
||||
* @push_data: Array of callback to send datums to iio sensor object.
|
||||
*/
|
||||
struct cros_ec_sensorhub {
|
||||
struct device *dev;
|
||||
struct cros_ec_dev *ec;
|
||||
int sensor_num;
|
||||
|
||||
struct cros_ec_command *msg;
|
||||
struct ec_params_motion_sense *params;
|
||||
struct ec_response_motion_sense *resp;
|
||||
struct mutex cmd_lock; /* Lock for protecting msg structure. */
|
||||
|
||||
struct notifier_block notifier;
|
||||
|
||||
struct cros_ec_sensors_ring_sample *ring;
|
||||
|
||||
ktime_t fifo_timestamp[CROS_EC_SENSOR_ALL_TS];
|
||||
struct ec_response_motion_sense_fifo_info *fifo_info;
|
||||
int fifo_size;
|
||||
|
||||
struct cros_ec_sensors_ts_batch_state *batch_state;
|
||||
|
||||
struct cros_ec_sensors_ec_overflow_state overflow_a;
|
||||
struct cros_ec_sensors_ec_overflow_state overflow_b;
|
||||
|
||||
struct cros_ec_sensors_ts_filter_state filter;
|
||||
|
||||
int tight_timestamps;
|
||||
|
||||
s32 future_timestamp_count;
|
||||
s64 future_timestamp_total_ns;
|
||||
|
||||
struct cros_ec_sensorhub_sensor_push_data *push_data;
|
||||
};
|
||||
|
||||
int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub,
|
||||
u8 sensor_num,
|
||||
struct iio_dev *indio_dev,
|
||||
cros_ec_sensorhub_push_data_cb_t cb);
|
||||
|
||||
void cros_ec_sensorhub_unregister_push_data(struct cros_ec_sensorhub *sensorhub,
|
||||
u8 sensor_num);
|
||||
|
||||
int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub);
|
||||
void cros_ec_sensorhub_ring_remove(void *arg);
|
||||
int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub,
|
||||
bool on);
|
||||
|
||||
#endif /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ChromeOS EC Power Delivery Notifier Driver
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H
|
||||
#define __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
||||
int cros_usbpd_register_notify(struct notifier_block *nb);
|
||||
|
||||
void cros_usbpd_unregister_notify(struct notifier_block *nb);
|
||||
|
||||
#endif /* __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H */
|
|
@ -8,8 +8,8 @@
|
|||
#ifndef WILCO_EC_H
|
||||
#define WILCO_EC_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Message flags for using the mailbox() interface */
|
||||
#define WILCO_EC_FLAG_NO_RESPONSE BIT(0) /* EC does not respond */
|
||||
|
@ -17,6 +17,10 @@
|
|||
/* Normal commands have a maximum 32 bytes of data */
|
||||
#define EC_MAILBOX_DATA_SIZE 32
|
||||
|
||||
struct device;
|
||||
struct resource;
|
||||
struct platform_device;
|
||||
|
||||
/**
|
||||
* struct wilco_ec_device - Wilco Embedded Controller handle.
|
||||
* @dev: Device handle.
|
||||
|
|
Loading…
Reference in New Issue