mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
chrome platform changes for 5.19
cros_ec: * Fix wrong error handling path. * Clean-up patches. cros_ec_chardev: * Re-introduce cros_ec_cmd_xfer to fix ABI broken. cros_ec_lpcs: * Support the Framework Laptop. cros_ec_typec: * Fix NULL dereference. chromeos_acpi: * Add ChromeOS ACPI device driver. * Fix Sphinx errors when `make htmldocs`. misc: * Drop BUG_ON()s. -----BEGIN PGP SIGNATURE----- iIkEABYIADEWIQS0yQeDP3cjLyifNRUrxTEGBto89AUCYoxDdBMcdHp1bmdiaUBr ZXJuZWwub3JnAAoJECvFMQYG2jz0UtgA/i2XEXq9znb7BriG43ZvplcFD4sMVGcQ xz4V4jHjNWIPAQDPOf28QMybiBQv3wWpLrx+gBLhYxRvEoeWxmbwN0UHAA== =9qNL -----END PGP SIGNATURE----- Merge tag 'tag-chrome-platform-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux Pull chrome platform updates from Tzung-Bi Shih: "cros_ec: - Fix wrong error handling path - Clean-up patches cros_ec_chardev: - Re-introduce cros_ec_cmd_xfer to fix ABI broken cros_ec_lpcs: - Support the Framework Laptop cros_ec_typec: - Fix NULL dereference chromeos_acpi: - Add ChromeOS ACPI device driver - Fix Sphinx errors when `make htmldocs` misc: - Drop BUG_ON()s" * tag 'tag-chrome-platform-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: platform/chrome: Use imperative mood for ChromeOS ACPI sysfs ABI descriptions platform/chrome: Use tables for values lists of ChromeOS ACPI sysfs ABI platform/chrome: cros_ec_spi: drop BUG_ON() if `din` isn't large enough platform/chrome: cros_ec_spi: drop unneeded BUG_ON() platform/chrome: cros_ec_i2c: drop BUG_ON() in cros_ec_pkt_xfer_i2c() platform/chrome: cros_ec_proto: drop BUG_ON() in cros_ec_get_host_event() platform/chrome: cros_ec_proto: drop BUG_ON() in cros_ec_prepare_tx() platform/chrome: correct cros_ec_prepare_tx() usage platform/chrome: cros_ec_proto: drop unneeded BUG_ON() in prepare_packet() platform/chrome: Add ChromeOS ACPI device driver platform/chrome: cros_ec_typec: Check for EC driver platform/chrome: cros_ec_lpcs: reserve the MEC LPC I/O ports first platform/chrome: cros_ec_lpcs: detect the Framework Laptop platform/chrome: Re-introduce cros_ec_cmd_xfer and use it for ioctls platform/chrome: cros_ec: append newline to all logs platform/chrome: cros_ec: sort header inclusion alphabetically platform/chrome: cros_ec: determine `wake_enabled` in cros_ec_suspend() platform/chrome: cros_ec: remove unused variable `was_wake_device` platform/chrome: cros_ec: fix error handling in cros_ec_register()
This commit is contained in:
commit
f1f88bb51f
137
Documentation/ABI/testing/sysfs-driver-chromeos-acpi
Normal file
137
Documentation/ABI/testing/sysfs-driver-chromeos-acpi
Normal file
@ -0,0 +1,137 @@
|
||||
What: /sys/bus/platform/devices/GGL0001:*/BINF.2
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns active EC firmware of current boot (boolean).
|
||||
|
||||
== ===============================
|
||||
0 Read only (recovery) firmware.
|
||||
1 Rewritable firmware.
|
||||
== ===============================
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/BINF.3
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns main firmware type for current boot (integer).
|
||||
|
||||
== =====================================
|
||||
0 Recovery.
|
||||
1 Normal.
|
||||
2 Developer.
|
||||
3 Netboot (factory installation only).
|
||||
== =====================================
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/CHSW
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns switch position for Chrome OS specific hardware
|
||||
switches when the firmware is booted (integer).
|
||||
|
||||
==== ===========================================
|
||||
0 No changes.
|
||||
2 Recovery button was pressed.
|
||||
4 Recovery button was pressed (EC firmware).
|
||||
32 Developer switch was enabled.
|
||||
512 Firmware write protection was disabled.
|
||||
==== ===========================================
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/FMAP
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns physical memory address of the start of the main
|
||||
processor firmware flashmap.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/FRID
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns firmware version for the read-only portion of the
|
||||
main processor firmware.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/FWID
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns firmware version for the rewritable portion of the
|
||||
main processor firmware.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.0
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns type of the GPIO signal for the Chrome OS specific
|
||||
GPIO assignments (integer).
|
||||
|
||||
=========== ==================================
|
||||
1 Recovery button.
|
||||
2 Developer mode switch.
|
||||
3 Firmware write protection switch.
|
||||
256 to 511 Debug header GPIO 0 to GPIO 255.
|
||||
=========== ==================================
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.1
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns signal attributes of the GPIO signal (integer bitfield).
|
||||
|
||||
== =======================
|
||||
0 Signal is active low.
|
||||
1 Signal is active high.
|
||||
== =======================
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.2
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns the GPIO number on the specified GPIO
|
||||
controller.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.3
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns name of the GPIO controller.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/HWID
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns hardware ID for the Chromebook.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/MECK
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns the SHA-1 or SHA-256 hash that is read out of the
|
||||
Management Engine extended registers during boot. The hash
|
||||
is exported via ACPI so the OS can verify that the Management
|
||||
Engine firmware has not changed. If Management Engine is not
|
||||
present, or if the firmware was unable to read the extended registers, this buffer size can be zero.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/VBNV.0
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns offset in CMOS bank 0 of the verified boot non-volatile
|
||||
storage block, counting from the first writable CMOS byte
|
||||
(that is, 'offset = 0' is the byte following the 14 bytes of
|
||||
clock data).
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/VBNV.1
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Return the size in bytes of the verified boot non-volatile
|
||||
storage block.
|
||||
|
||||
What: /sys/bus/platform/devices/GGL0001:*/VDAT
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Description:
|
||||
Returns the verified boot data block shared between the
|
||||
firmware verification step and the kernel verification step
|
||||
(binary).
|
363
Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
Normal file
363
Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
Normal file
@ -0,0 +1,363 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=====================
|
||||
Chrome OS ACPI Device
|
||||
=====================
|
||||
|
||||
Hardware functionality specific to Chrome OS is exposed through a Chrome OS ACPI device.
|
||||
The plug and play ID of a Chrome OS ACPI device is GGL0001. GGL is a valid PNP ID of Google.
|
||||
PNP ID can be used with the ACPI devices according to the guidelines. The following ACPI
|
||||
objects are supported:
|
||||
|
||||
.. flat-table:: Supported ACPI Objects
|
||||
:widths: 1 2
|
||||
:header-rows: 1
|
||||
|
||||
* - Object
|
||||
- Description
|
||||
|
||||
* - CHSW
|
||||
- Chrome OS switch positions
|
||||
|
||||
* - HWID
|
||||
- Chrome OS hardware ID
|
||||
|
||||
* - FWID
|
||||
- Chrome OS firmware version
|
||||
|
||||
* - FRID
|
||||
- Chrome OS read-only firmware version
|
||||
|
||||
* - BINF
|
||||
- Chrome OS boot information
|
||||
|
||||
* - GPIO
|
||||
- Chrome OS GPIO assignments
|
||||
|
||||
* - VBNV
|
||||
- Chrome OS NVRAM locations
|
||||
|
||||
* - VDTA
|
||||
- Chrome OS verified boot data
|
||||
|
||||
* - FMAP
|
||||
- Chrome OS flashmap base address
|
||||
|
||||
* - MLST
|
||||
- Chrome OS method list
|
||||
|
||||
CHSW (Chrome OS switch positions)
|
||||
=================================
|
||||
This control method returns the switch positions for Chrome OS specific hardware switches.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
An integer containing the switch positions as bitfields:
|
||||
|
||||
.. flat-table::
|
||||
:widths: 1 2
|
||||
|
||||
* - 0x00000002
|
||||
- Recovery button was pressed when x86 firmware booted.
|
||||
|
||||
* - 0x00000004
|
||||
- Recovery button was pressed when EC firmware booted. (required if EC EEPROM is
|
||||
rewritable; otherwise optional)
|
||||
|
||||
* - 0x00000020
|
||||
- Developer switch was enabled when x86 firmware booted.
|
||||
|
||||
* - 0x00000200
|
||||
- Firmware write protection was disabled when x86 firmware booted. (required if
|
||||
firmware write protection is controlled through x86 BIOS; otherwise optional)
|
||||
|
||||
All other bits are reserved and should be set to 0.
|
||||
|
||||
HWID (Chrome OS hardware ID)
|
||||
============================
|
||||
This control method returns the hardware ID for the Chromebook.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A null-terminated ASCII string containing the hardware ID from the Model-Specific Data area of
|
||||
EEPROM.
|
||||
|
||||
Note that the hardware ID can be up to 256 characters long, including the terminating null.
|
||||
|
||||
FWID (Chrome OS firmware version)
|
||||
=================================
|
||||
This control method returns the firmware version for the rewritable portion of the main
|
||||
processor firmware.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A null-terminated ASCII string containing the complete firmware version for the rewritable
|
||||
portion of the main processor firmware.
|
||||
|
||||
FRID (Chrome OS read-only firmware version)
|
||||
===========================================
|
||||
This control method returns the firmware version for the read-only portion of the main
|
||||
processor firmware.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A null-terminated ASCII string containing the complete firmware version for the read-only
|
||||
(bootstrap + recovery ) portion of the main processor firmware.
|
||||
|
||||
BINF (Chrome OS boot information)
|
||||
=================================
|
||||
This control method returns information about the current boot.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
|
||||
.. code-block::
|
||||
|
||||
Package {
|
||||
Reserved1
|
||||
Reserved2
|
||||
Active EC Firmware
|
||||
Active Main Firmware Type
|
||||
Reserved5
|
||||
}
|
||||
|
||||
.. flat-table::
|
||||
:widths: 1 1 2
|
||||
:header-rows: 1
|
||||
|
||||
* - Field
|
||||
- Format
|
||||
- Description
|
||||
|
||||
* - Reserved1
|
||||
- DWORD
|
||||
- Set to 256 (0x100). This indicates this field is no longer used.
|
||||
|
||||
* - Reserved2
|
||||
- DWORD
|
||||
- Set to 256 (0x100). This indicates this field is no longer used.
|
||||
|
||||
* - Active EC firmware
|
||||
- DWORD
|
||||
- The EC firmware which was used during boot.
|
||||
|
||||
- 0 - Read-only (recovery) firmware
|
||||
- 1 - Rewritable firmware.
|
||||
|
||||
Set to 0 if EC firmware is always read-only.
|
||||
|
||||
* - Active Main Firmware Type
|
||||
- DWORD
|
||||
- The main firmware type which was used during boot.
|
||||
|
||||
- 0 - Recovery
|
||||
- 1 - Normal
|
||||
- 2 - Developer
|
||||
- 3 - netboot (factory installation only)
|
||||
|
||||
Other values are reserved.
|
||||
|
||||
* - Reserved5
|
||||
- DWORD
|
||||
- Set to 256 (0x100). This indicates this field is no longer used.
|
||||
|
||||
GPIO (Chrome OS GPIO assignments)
|
||||
=================================
|
||||
This control method returns information about Chrome OS specific GPIO assignments for
|
||||
Chrome OS hardware, so the kernel can directly control that hardware.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
.. code-block::
|
||||
|
||||
Package {
|
||||
Package {
|
||||
// First GPIO assignment
|
||||
Signal Type //DWORD
|
||||
Attributes //DWORD
|
||||
Controller Offset //DWORD
|
||||
Controller Name //ASCIIZ
|
||||
},
|
||||
...
|
||||
Package {
|
||||
// Last GPIO assignment
|
||||
Signal Type //DWORD
|
||||
Attributes //DWORD
|
||||
Controller Offset //DWORD
|
||||
Controller Name //ASCIIZ
|
||||
}
|
||||
}
|
||||
|
||||
Where ASCIIZ means a null-terminated ASCII string.
|
||||
|
||||
.. flat-table::
|
||||
:widths: 1 1 2
|
||||
:header-rows: 1
|
||||
|
||||
* - Field
|
||||
- Format
|
||||
- Description
|
||||
|
||||
* - Signal Type
|
||||
- DWORD
|
||||
- Type of GPIO signal
|
||||
|
||||
- 0x00000001 - Recovery button
|
||||
- 0x00000002 - Developer mode switch
|
||||
- 0x00000003 - Firmware write protection switch
|
||||
- 0x00000100 - Debug header GPIO 0
|
||||
- ...
|
||||
- 0x000001FF - Debug header GPIO 255
|
||||
|
||||
Other values are reserved.
|
||||
|
||||
* - Attributes
|
||||
- DWORD
|
||||
- Signal attributes as bitfields:
|
||||
|
||||
- 0x00000001 - Signal is active-high (for button, a GPIO value
|
||||
of 1 means the button is pressed; for switches, a GPIO value
|
||||
of 1 means the switch is enabled). If this bit is 0, the signal
|
||||
is active low. Set to 0 for debug header GPIOs.
|
||||
|
||||
* - Controller Offset
|
||||
- DWORD
|
||||
- GPIO number on the specified controller.
|
||||
|
||||
* - Controller Name
|
||||
- ASCIIZ
|
||||
- Name of the controller for the GPIO.
|
||||
Currently supported names:
|
||||
"NM10" - Intel NM10 chip
|
||||
|
||||
VBNV (Chrome OS NVRAM locations)
|
||||
================================
|
||||
This control method returns information about the NVRAM (CMOS) locations used to
|
||||
communicate with the BIOS.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
.. code-block::
|
||||
|
||||
Package {
|
||||
NV Storage Block Offset //DWORD
|
||||
NV Storage Block Size //DWORD
|
||||
}
|
||||
|
||||
.. flat-table::
|
||||
:widths: 1 1 2
|
||||
:header-rows: 1
|
||||
|
||||
* - Field
|
||||
- Format
|
||||
- Description
|
||||
|
||||
* - NV Storage Block Offset
|
||||
- DWORD
|
||||
- Offset in CMOS bank 0 of the verified boot non-volatile storage block, counting from
|
||||
the first writable CMOS byte (that is, offset=0 is the byte following the 14 bytes of
|
||||
clock data).
|
||||
|
||||
* - NV Storage Block Size
|
||||
- DWORD
|
||||
- Size in bytes of the verified boot non-volatile storage block.
|
||||
|
||||
FMAP (Chrome OS flashmap address)
|
||||
=================================
|
||||
This control method returns the physical memory address of the start of the main processor
|
||||
firmware flashmap.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
NoneResult code:
|
||||
----------------
|
||||
A DWORD containing the physical memory address of the start of the main processor firmware
|
||||
flashmap.
|
||||
|
||||
VDTA (Chrome OS verified boot data)
|
||||
===================================
|
||||
This control method returns the verified boot data block shared between the firmware
|
||||
verification step and the kernel verification step.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A buffer containing the verified boot data block.
|
||||
|
||||
MECK (Management Engine Checksum)
|
||||
=================================
|
||||
This control method returns the SHA-1 or SHA-256 hash that is read out of the Management
|
||||
Engine extended registers during boot. The hash is exported via ACPI so the OS can verify that
|
||||
the ME firmware has not changed. If Management Engine is not present, or if the firmware was
|
||||
unable to read the extended registers, this buffer can be zero.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A buffer containing the ME hash.
|
||||
|
||||
MLST (Chrome OS method list)
|
||||
============================
|
||||
This control method returns a list of the other control methods supported by the Chrome OS
|
||||
hardware device.
|
||||
|
||||
Arguments:
|
||||
----------
|
||||
None
|
||||
|
||||
Result code:
|
||||
------------
|
||||
A package containing a list of null-terminated ASCII strings, one for each control method
|
||||
supported by the Chrome OS hardware device, not including the MLST method itself.
|
||||
For this version of the specification, the result is:
|
||||
|
||||
.. code-block::
|
||||
|
||||
Package {
|
||||
"CHSW",
|
||||
"FWID",
|
||||
"HWID",
|
||||
"FRID",
|
||||
"BINF",
|
||||
"GPIO",
|
||||
"VBNV",
|
||||
"FMAP",
|
||||
"VDTA",
|
||||
"MECK"
|
||||
}
|
@ -29,3 +29,4 @@ ACPI Support
|
||||
non-d0-probe
|
||||
extcon-intel-int3496
|
||||
intel-pmc-mux
|
||||
chromeos-acpi-device
|
||||
|
@ -15,6 +15,17 @@ menuconfig CHROME_PLATFORMS
|
||||
|
||||
if CHROME_PLATFORMS
|
||||
|
||||
config CHROMEOS_ACPI
|
||||
tristate "ChromeOS specific ACPI extensions"
|
||||
depends on ACPI
|
||||
help
|
||||
This driver provides the firmware interface for the services
|
||||
exported through the ChromeOS interfaces when using ChromeOS
|
||||
ACPI firmware.
|
||||
|
||||
If you have an ACPI-compatible Chromebook, say Y or M here.
|
||||
The module will be called chromeos_acpi.
|
||||
|
||||
config CHROMEOS_LAPTOP
|
||||
tristate "Chrome OS Laptop"
|
||||
depends on I2C && DMI && X86
|
||||
|
@ -4,6 +4,7 @@
|
||||
CFLAGS_cros_ec_trace.o:= -I$(src)
|
||||
CFLAGS_cros_ec_sensorhub_ring.o:= -I$(src)
|
||||
|
||||
obj-$(CONFIG_CHROMEOS_ACPI) += chromeos_acpi.o
|
||||
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
|
||||
obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN) += chromeos_privacy_screen.o
|
||||
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
|
||||
|
257
drivers/platform/chrome/chromeos_acpi.c
Normal file
257
drivers/platform/chrome/chromeos_acpi.c
Normal file
@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ChromeOS specific ACPI extensions
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* This driver attaches to the ChromeOS ACPI device and then exports the
|
||||
* values reported by the ACPI in a sysfs directory. All values are
|
||||
* presented in the string form (numbers as decimal values) and can be
|
||||
* accessed as the contents of the appropriate read only files in the
|
||||
* sysfs directory tree.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define ACPI_ATTR_NAME_LEN 4
|
||||
|
||||
#define DEV_ATTR(_var, _name) \
|
||||
static struct device_attribute dev_attr_##_var = \
|
||||
__ATTR(_name, 0444, chromeos_first_level_attr_show, NULL);
|
||||
|
||||
#define GPIO_ATTR_GROUP(_group, _name, _num) \
|
||||
static umode_t attr_is_visible_gpio_##_num(struct kobject *kobj, \
|
||||
struct attribute *attr, int n) \
|
||||
{ \
|
||||
if (_num < chromeos_acpi_gpio_groups) \
|
||||
return attr->mode; \
|
||||
return 0; \
|
||||
} \
|
||||
static ssize_t chromeos_attr_show_gpio_##_num(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
char name[ACPI_ATTR_NAME_LEN + 1]; \
|
||||
int ret, num; \
|
||||
\
|
||||
ret = parse_attr_name(attr->attr.name, name, &num); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
return chromeos_acpi_evaluate_method(dev, _num, num, name, buf); \
|
||||
} \
|
||||
static struct device_attribute dev_attr_0_##_group = \
|
||||
__ATTR(GPIO.0, 0444, chromeos_attr_show_gpio_##_num, NULL); \
|
||||
static struct device_attribute dev_attr_1_##_group = \
|
||||
__ATTR(GPIO.1, 0444, chromeos_attr_show_gpio_##_num, NULL); \
|
||||
static struct device_attribute dev_attr_2_##_group = \
|
||||
__ATTR(GPIO.2, 0444, chromeos_attr_show_gpio_##_num, NULL); \
|
||||
static struct device_attribute dev_attr_3_##_group = \
|
||||
__ATTR(GPIO.3, 0444, chromeos_attr_show_gpio_##_num, NULL); \
|
||||
\
|
||||
static struct attribute *attrs_##_group[] = { \
|
||||
&dev_attr_0_##_group.attr, \
|
||||
&dev_attr_1_##_group.attr, \
|
||||
&dev_attr_2_##_group.attr, \
|
||||
&dev_attr_3_##_group.attr, \
|
||||
NULL \
|
||||
}; \
|
||||
static const struct attribute_group attr_group_##_group = { \
|
||||
.name = _name, \
|
||||
.is_visible = attr_is_visible_gpio_##_num, \
|
||||
.attrs = attrs_##_group, \
|
||||
};
|
||||
|
||||
static unsigned int chromeos_acpi_gpio_groups;
|
||||
|
||||
/* Parse the ACPI package and return the data related to that attribute */
|
||||
static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *obj,
|
||||
int pkg_num, int sub_pkg_num, char *name, char *buf)
|
||||
{
|
||||
union acpi_object *element = obj->package.elements;
|
||||
|
||||
if (pkg_num >= obj->package.count)
|
||||
return -EINVAL;
|
||||
element += pkg_num;
|
||||
|
||||
if (element->type == ACPI_TYPE_PACKAGE) {
|
||||
if (sub_pkg_num >= element->package.count)
|
||||
return -EINVAL;
|
||||
/* select sub element inside this package */
|
||||
element = element->package.elements;
|
||||
element += sub_pkg_num;
|
||||
}
|
||||
|
||||
switch (element->type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
return sysfs_emit(buf, "%d\n", (int)element->integer.value);
|
||||
case ACPI_TYPE_STRING:
|
||||
return sysfs_emit(buf, "%s\n", element->string.pointer);
|
||||
case ACPI_TYPE_BUFFER:
|
||||
return sysfs_emit(buf, "%s\n", element->buffer.pointer);
|
||||
default:
|
||||
dev_err(dev, "element type %d not supported\n", element->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int chromeos_acpi_evaluate_method(struct device *dev, int pkg_num, int sub_pkg_num,
|
||||
char *name, char *buf)
|
||||
{
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
int ret = -EINVAL;
|
||||
|
||||
status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (((union acpi_object *)output.pointer)->type == ACPI_TYPE_PACKAGE)
|
||||
ret = chromeos_acpi_handle_package(dev, output.pointer, pkg_num, sub_pkg_num,
|
||||
name, buf);
|
||||
|
||||
kfree(output.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_attr_name(const char *name, char *attr_name, int *attr_num)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = strscpy(attr_name, name, ACPI_ATTR_NAME_LEN + 1);
|
||||
if (ret == -E2BIG)
|
||||
return kstrtoint(&name[ACPI_ATTR_NAME_LEN + 1], 0, attr_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t chromeos_first_level_attr_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
char attr_name[ACPI_ATTR_NAME_LEN + 1];
|
||||
int ret, attr_num = 0;
|
||||
|
||||
ret = parse_attr_name(attr->attr.name, attr_name, &attr_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
return chromeos_acpi_evaluate_method(dev, attr_num, 0, attr_name, buf);
|
||||
}
|
||||
|
||||
static unsigned int get_gpio_pkg_num(struct device *dev)
|
||||
{
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
unsigned int count = 0;
|
||||
char *name = "GPIO";
|
||||
|
||||
status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
|
||||
return count;
|
||||
}
|
||||
|
||||
obj = output.pointer;
|
||||
|
||||
if (obj->type == ACPI_TYPE_PACKAGE)
|
||||
count = obj->package.count;
|
||||
|
||||
kfree(output.pointer);
|
||||
return count;
|
||||
}
|
||||
|
||||
DEV_ATTR(binf2, BINF.2)
|
||||
DEV_ATTR(binf3, BINF.3)
|
||||
DEV_ATTR(chsw, CHSW)
|
||||
DEV_ATTR(fmap, FMAP)
|
||||
DEV_ATTR(frid, FRID)
|
||||
DEV_ATTR(fwid, FWID)
|
||||
DEV_ATTR(hwid, HWID)
|
||||
DEV_ATTR(meck, MECK)
|
||||
DEV_ATTR(vbnv0, VBNV.0)
|
||||
DEV_ATTR(vbnv1, VBNV.1)
|
||||
DEV_ATTR(vdat, VDAT)
|
||||
|
||||
static struct attribute *first_level_attrs[] = {
|
||||
&dev_attr_binf2.attr,
|
||||
&dev_attr_binf3.attr,
|
||||
&dev_attr_chsw.attr,
|
||||
&dev_attr_fmap.attr,
|
||||
&dev_attr_frid.attr,
|
||||
&dev_attr_fwid.attr,
|
||||
&dev_attr_hwid.attr,
|
||||
&dev_attr_meck.attr,
|
||||
&dev_attr_vbnv0.attr,
|
||||
&dev_attr_vbnv1.attr,
|
||||
&dev_attr_vdat.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group first_level_attr_group = {
|
||||
.attrs = first_level_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Every platform can have a different number of GPIO attribute groups.
|
||||
* Define upper limit groups. At run time, the platform decides to show
|
||||
* the present number of groups only, others are hidden.
|
||||
*/
|
||||
GPIO_ATTR_GROUP(gpio0, "GPIO.0", 0)
|
||||
GPIO_ATTR_GROUP(gpio1, "GPIO.1", 1)
|
||||
GPIO_ATTR_GROUP(gpio2, "GPIO.2", 2)
|
||||
GPIO_ATTR_GROUP(gpio3, "GPIO.3", 3)
|
||||
GPIO_ATTR_GROUP(gpio4, "GPIO.4", 4)
|
||||
GPIO_ATTR_GROUP(gpio5, "GPIO.5", 5)
|
||||
GPIO_ATTR_GROUP(gpio6, "GPIO.6", 6)
|
||||
GPIO_ATTR_GROUP(gpio7, "GPIO.7", 7)
|
||||
|
||||
static const struct attribute_group *chromeos_acpi_all_groups[] = {
|
||||
&first_level_attr_group,
|
||||
&attr_group_gpio0,
|
||||
&attr_group_gpio1,
|
||||
&attr_group_gpio2,
|
||||
&attr_group_gpio3,
|
||||
&attr_group_gpio4,
|
||||
&attr_group_gpio5,
|
||||
&attr_group_gpio6,
|
||||
&attr_group_gpio7,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int chromeos_acpi_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
chromeos_acpi_gpio_groups = get_gpio_pkg_num(&pdev->dev);
|
||||
|
||||
/*
|
||||
* If the platform has more GPIO attribute groups than the number of
|
||||
* groups this driver supports, give out a warning message.
|
||||
*/
|
||||
if (chromeos_acpi_gpio_groups > ARRAY_SIZE(chromeos_acpi_all_groups) - 2)
|
||||
dev_warn(&pdev->dev, "Only %zu GPIO attr groups supported by the driver out of total %u.\n",
|
||||
ARRAY_SIZE(chromeos_acpi_all_groups) - 2, chromeos_acpi_gpio_groups);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GGL is valid PNP ID of Google. PNP ID can be used with the ACPI devices. */
|
||||
static const struct acpi_device_id chromeos_device_ids[] = {
|
||||
{ "GGL0001", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);
|
||||
|
||||
static struct platform_driver chromeos_acpi_device_driver = {
|
||||
.probe = chromeos_acpi_device_probe,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.dev_groups = chromeos_acpi_all_groups,
|
||||
.acpi_match_table = chromeos_device_ids,
|
||||
}
|
||||
};
|
||||
module_platform_driver(chromeos_acpi_device_driver);
|
||||
|
||||
MODULE_AUTHOR("Muhammad Usama Anjum <usama.anjum@collabora.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ChromeOS specific ACPI extensions");
|
@ -9,12 +9,12 @@
|
||||
* battery charging and regulator control, firmware update.
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "cros_ec.h"
|
||||
@ -189,6 +189,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
ec_dev->max_request = sizeof(struct ec_params_hello);
|
||||
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
|
||||
ec_dev->max_passthru = 0;
|
||||
ec_dev->ec = NULL;
|
||||
ec_dev->pd = NULL;
|
||||
|
||||
ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
|
||||
if (!ec_dev->din)
|
||||
@ -213,7 +215,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"chromeos-ec", ec_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d",
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n",
|
||||
ec_dev->irq, err);
|
||||
return err;
|
||||
}
|
||||
@ -245,18 +247,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
if (IS_ERR(ec_dev->pd)) {
|
||||
dev_err(ec_dev->dev,
|
||||
"Failed to create CrOS PD platform device\n");
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
return PTR_ERR(ec_dev->pd);
|
||||
err = PTR_ERR(ec_dev->pd);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
err = devm_of_platform_populate(dev);
|
||||
if (err) {
|
||||
platform_device_unregister(ec_dev->pd);
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
dev_err(dev, "Failed to register sub-devices\n");
|
||||
return err;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +266,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
*/
|
||||
err = cros_ec_sleep_event(ec_dev, 0);
|
||||
if (err < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
|
||||
dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec\n",
|
||||
err);
|
||||
|
||||
if (ec_dev->mkbp_event_supported) {
|
||||
@ -278,7 +278,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
err = blocking_notifier_chain_register(&ec_dev->event_notifier,
|
||||
&ec_dev->notifier_ready);
|
||||
if (err)
|
||||
return err;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
@ -291,6 +291,10 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
cros_ec_irq_thread(0, ec_dev);
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
platform_device_unregister(ec_dev->pd);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_register);
|
||||
|
||||
@ -331,14 +335,15 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec",
|
||||
dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec\n",
|
||||
ret);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
|
||||
else
|
||||
ec_dev->wake_enabled = false;
|
||||
|
||||
disable_irq(ec_dev->irq);
|
||||
ec_dev->was_wake_device = ec_dev->wake_enabled;
|
||||
ec_dev->suspended = true;
|
||||
|
||||
return 0;
|
||||
@ -375,13 +380,12 @@ int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
|
||||
dev_dbg(ec_dev->dev, "Error %d sending resume event to ec\n",
|
||||
ret);
|
||||
|
||||
if (ec_dev->wake_enabled) {
|
||||
if (ec_dev->wake_enabled)
|
||||
disable_irq_wake(ec_dev->irq);
|
||||
ec_dev->wake_enabled = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let the mfd devices know about events that occur during
|
||||
* suspend. This way the clients know what to do with them.
|
||||
|
@ -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_status(ec->ec_dev, s_cmd);
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
|
||||
/* Only copy data to userland if data was received. */
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
@ -72,13 +72,19 @@ static int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev,
|
||||
i2c_msg[1].flags = I2C_M_RD;
|
||||
|
||||
packet_len = msg->insize + response_header_size;
|
||||
BUG_ON(packet_len > ec_dev->din_size);
|
||||
if (packet_len > ec_dev->din_size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
in_buf = ec_dev->din;
|
||||
i2c_msg[1].len = packet_len;
|
||||
i2c_msg[1].buf = (char *) in_buf;
|
||||
|
||||
packet_len = msg->outsize + request_header_size;
|
||||
BUG_ON(packet_len > ec_dev->dout_size);
|
||||
if (packet_len > ec_dev->dout_size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
out_buf = ec_dev->dout;
|
||||
i2c_msg[0].len = packet_len;
|
||||
i2c_msg[0].buf = (char *) out_buf;
|
||||
@ -89,6 +95,8 @@ static int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev,
|
||||
|
||||
ec_dev->dout++;
|
||||
ret = cros_ec_prepare_tx(ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
ec_dev->dout--;
|
||||
|
||||
/* send command to EC and read answer */
|
||||
|
@ -521,7 +521,9 @@ static int cros_ec_pkt_xfer_ish(struct cros_ec_device *ec_dev,
|
||||
out_msg->hdr.status = 0;
|
||||
|
||||
ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE;
|
||||
cros_ec_prepare_tx(ec_dev, msg);
|
||||
rv = cros_ec_prepare_tx(ec_dev, msg);
|
||||
if (rv < 0)
|
||||
goto end_error;
|
||||
ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE;
|
||||
|
||||
dev_dbg(dev,
|
||||
|
@ -147,6 +147,8 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
|
||||
u8 *dout;
|
||||
|
||||
ret = cros_ec_prepare_tx(ec, msg);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
/* Write buffer */
|
||||
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
|
||||
@ -341,9 +343,14 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
|
||||
u8 buf[2];
|
||||
int irq, ret;
|
||||
|
||||
if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
|
||||
dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve memmap region\n");
|
||||
/*
|
||||
* The Framework Laptop (and possibly other non-ChromeOS devices)
|
||||
* only exposes the eight I/O ports that are required for the Microchip EC.
|
||||
* Requesting a larger reservation will fail.
|
||||
*/
|
||||
if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
|
||||
EC_HOST_CMD_MEC_REGION_SIZE, dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve MEC region\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -357,6 +364,12 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
|
||||
cros_ec_lpc_ops.write = cros_ec_lpc_mec_write_bytes;
|
||||
cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
|
||||
if (buf[0] != 'E' || buf[1] != 'C') {
|
||||
if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
|
||||
dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve memmap region\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Re-assign read/write operations for the non MEC variant */
|
||||
cros_ec_lpc_ops.read = cros_ec_lpc_read_bytes;
|
||||
cros_ec_lpc_ops.write = cros_ec_lpc_write_bytes;
|
||||
@ -366,17 +379,19 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "EC ID not detected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
|
||||
EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve region0\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!devm_request_region(dev, EC_HOST_CMD_REGION1,
|
||||
EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve region1\n");
|
||||
return -EBUSY;
|
||||
/* Reserve the remaining I/O ports required by the non-MEC protocol. */
|
||||
if (!devm_request_region(dev, EC_HOST_CMD_REGION0 + EC_HOST_CMD_MEC_REGION_SIZE,
|
||||
EC_HOST_CMD_REGION_SIZE - EC_HOST_CMD_MEC_REGION_SIZE,
|
||||
dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve remainder of region0\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!devm_request_region(dev, EC_HOST_CMD_REGION1,
|
||||
EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
|
||||
dev_err(dev, "couldn't reserve region1\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
|
||||
@ -502,6 +517,14 @@ static const struct dmi_system_id cros_ec_lpc_dmi_table[] __initconst = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),
|
||||
},
|
||||
},
|
||||
/* A small number of non-Chromebook/box machines also use the ChromeOS EC */
|
||||
{
|
||||
/* the Framework Laptop */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop"),
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table);
|
||||
|
@ -60,8 +60,8 @@ static int prepare_packet(struct cros_ec_device *ec_dev,
|
||||
int i;
|
||||
u8 csum = 0;
|
||||
|
||||
BUG_ON(ec_dev->proto_version != EC_HOST_REQUEST_VERSION);
|
||||
BUG_ON(msg->outsize + sizeof(*request) > ec_dev->dout_size);
|
||||
if (msg->outsize + sizeof(*request) > ec_dev->dout_size)
|
||||
return -EINVAL;
|
||||
|
||||
out = ec_dev->dout;
|
||||
request = (struct ec_host_request *)out;
|
||||
@ -165,7 +165,7 @@ static int send_command(struct cros_ec_device *ec_dev,
|
||||
* only SPI uses it. Once LPC uses the same protocol it can start using it.
|
||||
* I2C could use it now, with a refactor of the existing code.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
* Return: number of prepared bytes on success or negative error code.
|
||||
*/
|
||||
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
@ -177,7 +177,9 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
if (ec_dev->proto_version > 2)
|
||||
return prepare_packet(ec_dev, msg);
|
||||
|
||||
BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
|
||||
if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
out = ec_dev->dout;
|
||||
out[0] = EC_CMD_VERSION0 + msg->version;
|
||||
out[1] = msg->command;
|
||||
@ -560,22 +562,28 @@ exit:
|
||||
EXPORT_SYMBOL(cros_ec_query_all);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
|
||||
* cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
|
||||
* cmd_xfer() callback directly. It returns success status only if both the command was transmitted
|
||||
* successfully and the EC replied with success status.
|
||||
* Call this to send a command to the ChromeOS EC. This should be used instead
|
||||
* of calling the EC's cmd_xfer() callback directly. This function does not
|
||||
* convert EC command execution error codes to Linux error codes. Most
|
||||
* in-kernel users will want to use cros_ec_cmd_xfer_status() instead since
|
||||
* that function implements the conversion.
|
||||
*
|
||||
* Return:
|
||||
* >=0 - The number of bytes transferred
|
||||
* <0 - Linux error code
|
||||
* >0 - EC command was executed successfully. The return value is the number
|
||||
* of bytes returned by the EC (excluding the header).
|
||||
* =0 - EC communication was successful. EC command execution results are
|
||||
* reported in msg->result. The result will be EC_RES_SUCCESS if the
|
||||
* command was executed successfully or report an EC command execution
|
||||
* error.
|
||||
* <0 - EC communication error. Return value is the Linux error code.
|
||||
*/
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
int ret, mapped;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ec_dev->lock);
|
||||
if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {
|
||||
@ -616,6 +624,32 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
ret = send_command(ec_dev, msg);
|
||||
mutex_unlock(&ec_dev->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_cmd_xfer);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
|
||||
* cmd_xfer() callback directly. It returns success status only if both the command was transmitted
|
||||
* successfully and the EC replied with success status.
|
||||
*
|
||||
* Return:
|
||||
* >=0 - The number of bytes transferred.
|
||||
* <0 - Linux error code
|
||||
*/
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
{
|
||||
int ret, mapped;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mapped = cros_ec_map_error(msg->result);
|
||||
if (mapped) {
|
||||
dev_dbg(ec_dev->dev, "Command result (err: %d [%d])\n",
|
||||
@ -783,7 +817,8 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
u32 host_event;
|
||||
|
||||
BUG_ON(!ec_dev->mkbp_event_supported);
|
||||
if (!ec_dev->mkbp_event_supported)
|
||||
return 0;
|
||||
|
||||
if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)
|
||||
return 0;
|
||||
|
@ -89,6 +89,8 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
|
||||
|
||||
ec_msg->result = 0;
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
if (len < 0)
|
||||
return len;
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
reinit_completion(&ec_rpmsg->xfer_ack);
|
||||
|
@ -160,7 +160,8 @@ static int receive_n_bytes(struct cros_ec_device *ec_dev, u8 *buf, int n)
|
||||
struct spi_message msg;
|
||||
int ret;
|
||||
|
||||
BUG_ON(buf - ec_dev->din + n > ec_dev->din_size);
|
||||
if (buf - ec_dev->din + n > ec_dev->din_size)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&trans, 0, sizeof(trans));
|
||||
trans.cs_change = 1;
|
||||
@ -197,7 +198,8 @@ static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev,
|
||||
unsigned long deadline;
|
||||
int todo;
|
||||
|
||||
BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
|
||||
if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
/* Receive data until we see the header byte */
|
||||
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
|
||||
@ -237,7 +239,6 @@ static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev,
|
||||
* start of our buffer
|
||||
*/
|
||||
todo = end - ++ptr;
|
||||
BUG_ON(todo < 0 || todo > ec_dev->din_size);
|
||||
todo = min(todo, need_len);
|
||||
memmove(ec_dev->din, ptr, todo);
|
||||
ptr = ec_dev->din + todo;
|
||||
@ -305,7 +306,8 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
||||
unsigned long deadline;
|
||||
int todo;
|
||||
|
||||
BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
|
||||
if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
/* Receive data until we see the header byte */
|
||||
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
|
||||
@ -345,7 +347,6 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
||||
* start of our buffer
|
||||
*/
|
||||
todo = end - ++ptr;
|
||||
BUG_ON(todo < 0 || todo > ec_dev->din_size);
|
||||
todo = min(todo, need_len);
|
||||
memmove(ec_dev->din, ptr, todo);
|
||||
ptr = ec_dev->din + todo;
|
||||
@ -401,6 +402,8 @@ static int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
||||
unsigned long delay;
|
||||
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
if (len < 0)
|
||||
return len;
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
/* If it's too soon to do another transaction, wait */
|
||||
@ -544,6 +547,8 @@ static int do_cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
|
||||
unsigned long delay;
|
||||
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
if (len < 0)
|
||||
return len;
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
/* If it's too soon to do another transaction, wait */
|
||||
|
@ -1084,6 +1084,9 @@ static int cros_typec_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ec_dev = dev_get_drvdata(&typec->ec->ec->dev);
|
||||
if (!ec_dev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
|
||||
typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
|
||||
|
||||
|
@ -51,10 +51,14 @@
|
||||
/*
|
||||
* The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff
|
||||
* and they tell the kernel that so we have to think of it as two parts.
|
||||
*
|
||||
* Other BIOSes report only the I/O port region spanned by the Microchip
|
||||
* MEC series EC; an attempt to address a larger region may fail.
|
||||
*/
|
||||
#define EC_HOST_CMD_REGION0 0x800
|
||||
#define EC_HOST_CMD_REGION1 0x880
|
||||
#define EC_HOST_CMD_REGION_SIZE 0x80
|
||||
#define EC_HOST_CMD_REGION0 0x800
|
||||
#define EC_HOST_CMD_REGION1 0x880
|
||||
#define EC_HOST_CMD_REGION_SIZE 0x80
|
||||
#define EC_HOST_CMD_MEC_REGION_SIZE 0x8
|
||||
|
||||
/* EC command register bit functions */
|
||||
#define EC_LPC_CMDR_DATA BIT(0) /* Data ready for host to read */
|
||||
|
@ -76,8 +76,6 @@ struct cros_ec_command {
|
||||
* struct cros_ec_device - Information about a ChromeOS EC device.
|
||||
* @phys_name: Name of physical comms layer (e.g. 'i2c-4').
|
||||
* @dev: Device pointer for physical comms device
|
||||
* @was_wake_device: True if this device was set to wake the system from
|
||||
* sleep at the last suspend.
|
||||
* @cros_class: The class structure for this device.
|
||||
* @cmd_readmem: Direct read of the EC memory-mapped region, if supported.
|
||||
* @offset: Is within EC_LPC_ADDR_MEMMAP region.
|
||||
@ -137,7 +135,6 @@ struct cros_ec_device {
|
||||
/* These are used by other drivers that want to talk to the EC */
|
||||
const char *phys_name;
|
||||
struct device *dev;
|
||||
bool was_wake_device;
|
||||
struct class *cros_class;
|
||||
int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset,
|
||||
unsigned int bytes, void *dest);
|
||||
@ -216,6 +213,9 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
int cros_ec_check_result(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user