diff options
Diffstat (limited to 'drivers')
40 files changed, 2241 insertions, 136 deletions
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 981fba56bc18..1621f2f7f129 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -24,8 +24,6 @@ #include <linux/notifier.h> #include <linux/extcon-provider.h> #include <linux/regmap.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> #include <linux/mfd/axp20x.h> /* Power source status register */ @@ -79,11 +77,6 @@ enum axp288_extcon_reg { AXP288_BC_DET_STAT_REG = 0x2f, }; -enum axp288_mux_select { - EXTCON_GPIO_MUX_SEL_PMIC = 0, - EXTCON_GPIO_MUX_SEL_SOC, -}; - enum axp288_extcon_irq { VBUS_FALLING_IRQ = 0, VBUS_RISING_IRQ, @@ -104,10 +97,8 @@ struct axp288_extcon_info { struct device *dev; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; - struct gpio_desc *gpio_mux_cntl; int irq[EXTCON_IRQ_END]; struct extcon_dev *edev; - struct notifier_block extcon_nb; unsigned int previous_cable; }; @@ -197,15 +188,6 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) } no_vbus: - /* - * If VBUS is absent Connect D+/D- lines to PMIC for BC - * detection. Else connect them to SOC for USB communication. - */ - if (info->gpio_mux_cntl) - gpiod_set_value(info->gpio_mux_cntl, - vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC - : EXTCON_GPIO_MUX_SEL_PMIC); - extcon_set_state_sync(info->edev, info->previous_cable, false); if (info->previous_cable == EXTCON_CHG_USB_SDP) extcon_set_state_sync(info->edev, EXTCON_USB, false); @@ -253,8 +235,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) { struct axp288_extcon_info *info; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct axp288_extcon_pdata *pdata = pdev->dev.platform_data; - int ret, i, pirq, gpio; + int ret, i, pirq; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -264,8 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev) info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->previous_cable = EXTCON_NONE; - if (pdata) - info->gpio_mux_cntl = pdata->gpio_mux_cntl; platform_set_drvdata(pdev, info); @@ -286,21 +265,11 @@ static int axp288_extcon_probe(struct platform_device *pdev) return ret; } - /* Set up gpio control for USB Mux */ - if (info->gpio_mux_cntl) { - gpio = desc_to_gpio(info->gpio_mux_cntl); - ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX"); - if (ret < 0) { - dev_err(&pdev->dev, - "failed to request the gpio=%d\n", gpio); - return ret; - } - gpiod_direction_output(info->gpio_mux_cntl, - EXTCON_GPIO_MUX_SEL_PMIC); - } - for (i = 0; i < EXTCON_IRQ_END; i++) { pirq = platform_get_irq(pdev, i); + if (pirq < 0) + return pirq; + info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); if (info->irq[i] < 0) { dev_err(&pdev->dev, diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c index 6187f731b29d..6721ab01fe7d 100644 --- a/drivers/extcon/extcon-usbc-cros-ec.c +++ b/drivers/extcon/extcon-usbc-cros-ec.c @@ -34,16 +34,26 @@ struct cros_ec_extcon_info { struct notifier_block notifier; + unsigned int dr; /* data role */ + bool pr; /* power role (true if VBUS enabled) */ bool dp; /* DisplayPort enabled */ bool mux; /* SuperSpeed (usb3) enabled */ unsigned int power_type; }; static const unsigned int usb_type_c_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, EXTCON_DISP_DP, EXTCON_NONE, }; +enum usb_data_roles { + DR_NONE, + DR_HOST, + DR_DEVICE, +}; + /** * cros_ec_pd_command() - Send a command to the EC. * @info: pointer to struct cros_ec_extcon_info @@ -150,6 +160,7 @@ static int cros_ec_usb_get_role(struct cros_ec_extcon_info *info, pd_control.port = info->port_id; pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE; pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE; + pd_control.swap = USB_PD_CTRL_SWAP_NONE; ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1, &pd_control, sizeof(pd_control), &resp, sizeof(resp)); @@ -183,11 +194,72 @@ static int cros_ec_pd_get_num_ports(struct cros_ec_extcon_info *info) return resp.num_ports; } +static const char *cros_ec_usb_role_string(unsigned int role) +{ + return role == DR_NONE ? "DISCONNECTED" : + (role == DR_HOST ? "DFP" : "UFP"); +} + +static const char *cros_ec_usb_power_type_string(unsigned int type) +{ + switch (type) { + case USB_CHG_TYPE_NONE: + return "USB_CHG_TYPE_NONE"; + case USB_CHG_TYPE_PD: + return "USB_CHG_TYPE_PD"; + case USB_CHG_TYPE_PROPRIETARY: + return "USB_CHG_TYPE_PROPRIETARY"; + case USB_CHG_TYPE_C: + return "USB_CHG_TYPE_C"; + case USB_CHG_TYPE_BC12_DCP: + return "USB_CHG_TYPE_BC12_DCP"; + case USB_CHG_TYPE_BC12_CDP: + return "USB_CHG_TYPE_BC12_CDP"; + case USB_CHG_TYPE_BC12_SDP: + return "USB_CHG_TYPE_BC12_SDP"; + case USB_CHG_TYPE_OTHER: + return "USB_CHG_TYPE_OTHER"; + case USB_CHG_TYPE_VBUS: + return "USB_CHG_TYPE_VBUS"; + case USB_CHG_TYPE_UNKNOWN: + return "USB_CHG_TYPE_UNKNOWN"; + default: + return "USB_CHG_TYPE_UNKNOWN"; + } +} + +static bool cros_ec_usb_power_type_is_wall_wart(unsigned int type, + unsigned int role) +{ + switch (type) { + /* FIXME : Guppy, Donnettes, and other chargers will be miscategorized + * because they identify with USB_CHG_TYPE_C, but we can't return true + * here from that code because that breaks Suzy-Q and other kinds of + * USB Type-C cables and peripherals. + */ + case USB_CHG_TYPE_PROPRIETARY: + case USB_CHG_TYPE_BC12_DCP: + return true; + case USB_CHG_TYPE_PD: + case USB_CHG_TYPE_C: + case USB_CHG_TYPE_BC12_CDP: + case USB_CHG_TYPE_BC12_SDP: + case USB_CHG_TYPE_OTHER: + case USB_CHG_TYPE_VBUS: + case USB_CHG_TYPE_UNKNOWN: + case USB_CHG_TYPE_NONE: + default: + return false; + } +} + static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, bool force) { struct device *dev = info->dev; int role, power_type; + unsigned int dr = DR_NONE; + bool pr = false; bool polarity = false; bool dp = false; bool mux = false; @@ -206,9 +278,12 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, dev_err(dev, "failed getting role err = %d\n", role); return role; } + dev_dbg(dev, "disconnected\n"); } else { int pd_mux_state; + dr = (role & PD_CTRL_RESP_ROLE_DATA) ? DR_HOST : DR_DEVICE; + pr = (role & PD_CTRL_RESP_ROLE_POWER); pd_mux_state = cros_ec_usb_get_pd_mux_state(info); if (pd_mux_state < 0) pd_mux_state = USB_PD_MUX_USB_ENABLED; @@ -216,20 +291,62 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, dp = pd_mux_state & USB_PD_MUX_DP_ENABLED; mux = pd_mux_state & USB_PD_MUX_USB_ENABLED; hpd = pd_mux_state & USB_PD_MUX_HPD_IRQ; - } - if (force || info->dp != dp || info->mux != mux || - info->power_type != power_type) { + dev_dbg(dev, + "connected role 0x%x pwr type %d dr %d pr %d pol %d mux %d dp %d hpd %d\n", + role, power_type, dr, pr, polarity, mux, dp, hpd); + } + /* + * When there is no USB host (e.g. USB PD charger), + * we are not really a UFP for the AP. + */ + if (dr == DR_DEVICE && + cros_ec_usb_power_type_is_wall_wart(power_type, role)) + dr = DR_NONE; + + if (force || info->dr != dr || info->pr != pr || info->dp != dp || + info->mux != mux || info->power_type != power_type) { + bool host_connected = false, device_connected = false; + + dev_dbg(dev, "Type/Role switch! type = %s role = %s\n", + cros_ec_usb_power_type_string(power_type), + cros_ec_usb_role_string(dr)); + info->dr = dr; + info->pr = pr; info->dp = dp; info->mux = mux; info->power_type = power_type; - extcon_set_state(info->edev, EXTCON_DISP_DP, dp); + if (dr == DR_DEVICE) + device_connected = true; + else if (dr == DR_HOST) + host_connected = true; + extcon_set_state(info->edev, EXTCON_USB, device_connected); + extcon_set_state(info->edev, EXTCON_USB_HOST, host_connected); + extcon_set_state(info->edev, EXTCON_DISP_DP, dp); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)pr); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)pr); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); extcon_set_property(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_TYPEC_POLARITY, (union extcon_property_value)(int)polarity); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)mux); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)mux); extcon_set_property(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS, (union extcon_property_value)(int)mux); @@ -237,6 +354,8 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, EXTCON_PROP_DISP_HPD, (union extcon_property_value)(int)hpd); + extcon_sync(info->edev, EXTCON_USB); + extcon_sync(info->edev, EXTCON_USB_HOST); extcon_sync(info->edev, EXTCON_DISP_DP); } else if (hpd) { @@ -322,13 +441,28 @@ static int extcon_cros_ec_probe(struct platform_device *pdev) return ret; } + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_DISP_HPD); + info->dr = DR_NONE; + info->pr = false; + platform_set_drvdata(pdev, info); /* Get PD events from the EC */ diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index a52674327857..8988ba3b2d65 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -106,7 +106,7 @@ static int pm8058_led_probe(struct platform_device *pdev) if (!led) return -ENOMEM; - led->ledtype = (u32)of_device_get_match_data(&pdev->dev); + led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev); map = dev_get_regmap(pdev->dev.parent, NULL); if (!map) { diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index 7310e32b5991..aa2b0786bbe9 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -45,7 +45,7 @@ config MEMSTICK_R592 config MEMSTICK_REALTEK_PCI tristate "Realtek PCI-E Memstick Card Interface Driver" - depends on MFD_RTSX_PCI + depends on MISC_RTSX_PCI help Say Y here to include driver code to support Memstick card interface of Realtek PCI-E card reader @@ -55,7 +55,7 @@ config MEMSTICK_REALTEK_PCI config MEMSTICK_REALTEK_USB tristate "Realtek USB Memstick Card Interface Driver" - depends on MFD_RTSX_USB + depends on MISC_RTSX_USB help Say Y here to include driver code to support Memstick card interface of Realtek RTS5129/39 series USB card reader diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c index 818fa94354ae..a44b4578ba4d 100644 --- a/drivers/memstick/host/rtsx_pci_ms.c +++ b/drivers/memstick/host/rtsx_pci_ms.c @@ -24,7 +24,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/memstick.h> -#include <linux/mfd/rtsx_pci.h> +#include <linux/rtsx_pci.h> #include <asm/unaligned.h> struct realtek_pci_ms { diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index 2e3cf012ef48..4f64563df7de 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -25,7 +25,7 @@ #include <linux/workqueue.h> #include <linux/memstick.h> #include <linux/kthread.h> -#include <linux/mfd/rtsx_usb.h> +#include <linux/rtsx_usb.h> #include <linux/pm_runtime.h> #include <linux/mutex.h> #include <linux/sched.h> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1d20a800e967..fb884fab0b8d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -222,6 +222,16 @@ config MFD_CROS_EC_SPI response time cannot be guaranteed, we support ignoring 'pre-amble' bytes before the response actually starts. +config MFD_CROS_EC_CHARDEV + tristate "Chrome OS Embedded Controller userspace device interface" + depends on MFD_CROS_EC + select CROS_EC_CTL + ---help--- + This driver adds support to talk with the ChromeOS EC from userspace. + + If you have a supported Chromebook, choose Y or M here. + The module will be called cros_ec_dev. + config MFD_ASIC3 bool "Compaq ASIC3" depends on GPIOLIB && ARM @@ -929,17 +939,6 @@ config MFD_RDC321X southbridge which provides access to GPIOs and Watchdog using the southbridge PCI device configuration space. -config MFD_RTSX_PCI - tristate "Realtek PCI-E card reader" - depends on PCI - select MFD_CORE - help - This supports for Realtek PCI-Express card reader including rts5209, - rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, etc. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick, Memory Stick Pro, Secure Digital and - MultiMediaCard. - config MFD_RT5033 tristate "Richtek RT5033 Power Management IC" depends on I2C @@ -953,16 +952,6 @@ config MFD_RT5033 sub-devices like charger, fuel gauge, flash LED, current source, LDO and Buck. -config MFD_RTSX_USB - tristate "Realtek USB card reader" - depends on USB - select MFD_CORE - help - Select this option to get support for Realtek USB 2.0 card readers - including RTS5129, RTS5139, RTS5179 and RTS5170. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick Pro, Secure Digital and MultiMediaCard. - config MFD_RC5T583 bool "Ricoh RC5T583 Power Management system device" depends on I2C=y @@ -1859,5 +1848,13 @@ config MFD_VEXPRESS_SYSREG System Registers are the platform configuration block on the ARM Ltd. Versatile Express board. +config RAVE_SP_CORE + tristate "RAVE SP MCU core driver" + depends on SERIAL_DEV_BUS + select CRC_CCITT + help + Select this to get support for the Supervisory Processor + device found on several devices in RAVE line of hardware. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d9474ade32e6..d9d2cf0d32ef 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -17,12 +17,9 @@ cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o -rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o -obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o -obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o - obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o @@ -230,3 +227,5 @@ obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o +obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o + diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index b0ca5a4c841e..d61024141e2b 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = { }; static const struct mfd_cell ec_cell = { - .name = "cros-ec-ctl", + .name = "cros-ec-dev", .platform_data = &ec_p, .pdata_size = sizeof(ec_p), }; static const struct mfd_cell ec_pd_cell = { - .name = "cros-ec-ctl", + .name = "cros-ec-dev", .platform_data = &pd_p, .pdata_size = sizeof(pd_p), }; diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index cf6c4f0846b8..e4fafdd96e5e 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -25,9 +25,10 @@ #include <linux/slab.h> #include <linux/uaccess.h> -#include "cros_ec_debugfs.h" #include "cros_ec_dev.h" +#define DRV_NAME "cros-ec-dev" + /* Device variables */ #define CROS_MAX_DEV 128 static int ec_major; @@ -461,7 +462,7 @@ static int ec_device_remove(struct platform_device *pdev) } static const struct platform_device_id cros_ec_id[] = { - { "cros-ec-ctl", 0 }, + { DRV_NAME, 0 }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(platform, cros_ec_id); @@ -493,7 +494,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = { static struct platform_driver cros_ec_dev_driver = { .driver = { - .name = "cros-ec-ctl", + .name = DRV_NAME, .pm = &cros_ec_dev_pm_ops, }, .probe = ec_device_probe, @@ -544,6 +545,7 @@ static void __exit cros_ec_dev_exit(void) module_init(cros_ec_dev_init); module_exit(cros_ec_dev_exit); +MODULE_ALIAS("platform:" DRV_NAME); MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>"); MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); MODULE_VERSION("1.0"); diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/mfd/cros_ec_dev.h index 45e9453608c5..45e9453608c5 100644 --- a/drivers/platform/chrome/cros_ec_dev.h +++ b/drivers/mfd/cros_ec_dev.h diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c new file mode 100644 index 000000000000..5c858e784a89 --- /dev/null +++ b/drivers/mfd/rave-sp.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Multifunction core driver for Zodiac Inflight Innovations RAVE + * Supervisory Processor(SP) MCU that is connected via dedicated UART + * port + * + * Copyright (C) 2017 Zodiac Inflight Innovations + */ + +#include <linux/atomic.h> +#include <linux/crc-ccitt.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/mfd/rave-sp.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/sched.h> +#include <linux/serdev.h> +#include <asm/unaligned.h> + +/* + * UART protocol using following entities: + * - message to MCU => ACK response + * - event from MCU => event ACK + * + * Frame structure: + * <STX> <DATA> <CHECKSUM> <ETX> + * Where: + * - STX - is start of transmission character + * - ETX - end of transmission + * - DATA - payload + * - CHECKSUM - checksum calculated on <DATA> + * + * If <DATA> or <CHECKSUM> contain one of control characters, then it is + * escaped using <DLE> control code. Added <DLE> does not participate in + * checksum calculation. + */ +#define RAVE_SP_STX 0x02 +#define RAVE_SP_ETX 0x03 +#define RAVE_SP_DLE 0x10 + +#define RAVE_SP_MAX_DATA_SIZE 64 +#define RAVE_SP_CHECKSUM_SIZE 2 /* Worst case scenario on RDU2 */ +/* + * We don't store STX, ETX and unescaped bytes, so Rx is only + * DATA + CSUM + */ +#define RAVE_SP_RX_BUFFER_SIZE \ + (RAVE_SP_MAX_DATA_SIZE + RAVE_SP_CHECKSUM_SIZE) + +#define RAVE_SP_STX_ETX_SIZE 2 +/* + * For Tx we have to have space for everything, STX, EXT and + * potentially stuffed DATA + CSUM data + csum + */ +#define RAVE_SP_TX_BUFFER_SIZE \ + (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) + +#define RAVE_SP_BOOT_SOURCE_GET 0 +#define RAVE_SP_BOOT_SOURCE_SET 1 + +#define RAVE_SP_RDU2_BOARD_TYPE_RMB 0 +#define RAVE_SP_RDU2_BOARD_TYPE_DEB 1 + +#define RAVE_SP_BOOT_SOURCE_SD 0 +#define RAVE_SP_BOOT_SOURCE_EMMC 1 +#define RAVE_SP_BOOT_SOURCE_NOR 2 + +/** + * enum rave_sp_deframer_state - Possible state for de-framer + * + * @RAVE_SP_EXPECT_SOF: Scanning input for start-of-frame marker + * @RAVE_SP_EXPECT_DATA: Got start of frame marker, collecting frame + * @RAVE_SP_EXPECT_ESCAPED_DATA: Got escape character, collecting escaped byte + */ +enum rave_sp_deframer_state { + RAVE_SP_EXPECT_SOF, + RAVE_SP_EXPECT_DATA, + RAVE_SP_EXPECT_ESCAPED_DATA, +}; + +/** + * struct rave_sp_deframer - Device protocol deframer + * + * @state: Current state of the deframer + * @data: Buffer used to collect deframed data + * @length: Number of bytes de-framed so far + */ +struct rave_sp_deframer { + enum rave_sp_deframer_state state; + unsigned char data[RAVE_SP_RX_BUFFER_SIZE]; + size_t length; +}; + +/** + * struct rave_sp_reply - Reply as per RAVE device protocol + * + * @length: Expected reply length + * @data: Buffer to store reply payload in + * @code: Expected reply code + * @ackid: Expected reply ACK ID + * @completion: Successful reply reception completion + */ +struct rave_sp_reply { + size_t length; + void *data; + u8 code; + u8 ackid; + struct completion received; +}; + +/** + * struct rave_sp_checksum - Variant specific checksum implementation details + * + * @length: Caculated checksum length + * @subroutine: Utilized checksum algorithm implementation + */ +struct rave_sp_checksum { + size_t length; + void (*subroutine)(const u8 *, size_t, u8 *); +}; + +/** + * struct rave_sp_variant_cmds - Variant specific command routines + * + * @translate: Generic to variant specific command mapping routine + * + */ +struct rave_sp_variant_cmds { + int (*translate)(enum rave_sp_command); +}; + +/** + * struct rave_sp_variant - RAVE supervisory processor core variant + * + * @checksum: Variant specific checksum implementation + * @cmd: Variant specific command pointer table + * + */ +struct rave_sp_variant { + const struct rave_sp_checksum *checksum; + struct rave_sp_variant_cmds cmd; +}; + +/** + * struct rave_sp - RAVE supervisory processor core + * + * @serdev: Pointer to underlying serdev + * @deframer: Stored state of the protocol deframer + * @ackid: ACK ID used in last reply sent to the device + * @bus_lock: Lock to serialize access to the device + * @reply_lock: Lock protecting @reply + * @reply: Pointer to memory to store reply payload + * + * @variant: Device variant specific information + * @event_notifier_list: Input event notification chain + * + */ +struct rave_sp { + struct serdev_device *serdev; + struct rave_sp_deframer deframer; + atomic_t ackid; + struct mutex bus_lock; + struct mutex reply_lock; + struct rave_sp_reply *reply; + + const struct rave_sp_variant *variant; + struct blocking_notifier_head event_notifier_list; +}; + +static bool rave_sp_id_is_event(u8 code) +{ + return (code & 0xF0) == RAVE_SP_EVNT_BASE; +} + +static void rave_sp_unregister_event_notifier(struct device *dev, void *res) +{ + struct rave_sp *sp = dev_get_drvdata(dev->parent); + struct notifier_block *nb = *(struct notifier_block **)res; + struct blocking_notifier_head *bnh = &sp->event_notifier_list; + + WARN_ON(blocki |
