aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-09-15 13:54:11 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-09-15 13:54:11 +0200
commitc1aa01c96e590714d99c5f17cfae1b14dec8bdee (patch)
tree5811422f65efdff3fd89fdaf9a8c6d7d1cc4d06b
parent4758ee8bc89a86c2110b9e85878538ced8045ef5 (diff)
downloadpatches-c1aa01c96e590714d99c5f17cfae1b14dec8bdee.tar.gz
greybus patches
-rw-r--r--greybus_arche.patch1404
-rw-r--r--greybus_audio.patch4636
-rw-r--r--greybus_bootrom.patch531
-rw-r--r--greybus_build.patch344
-rw-r--r--greybus_camera.patch1538
-rw-r--r--greybus_core.patch4431
-rw-r--r--greybus_docs.patch282
-rw-r--r--greybus_es2.patch1604
-rw-r--r--greybus_firmware.patch2429
-rw-r--r--greybus_gbphy.patch481
-rw-r--r--greybus_gpio.patch774
-rw-r--r--greybus_hd.patch358
-rw-r--r--greybus_hid.patch543
-rw-r--r--greybus_i2c.patch350
-rw-r--r--greybus_interface.patch1415
-rw-r--r--greybus_light.patch1366
-rw-r--r--greybus_log.patch139
-rw-r--r--greybus_loopback.patch1372
-rw-r--r--greybus_operations.patch1460
-rw-r--r--greybus_power.patch1148
-rw-r--r--greybus_protocol.patch2275
-rw-r--r--greybus_pwm.patch345
-rw-r--r--greybus_raw.patch388
-rw-r--r--greybus_sdio.patch891
-rw-r--r--greybus_spi.patch683
-rw-r--r--greybus_svc.patch1808
-rw-r--r--greybus_timesync.patch1494
-rw-r--r--greybus_tools.patch1435
-rw-r--r--greybus_trace.patch538
-rw-r--r--greybus_uart.patch1082
-rw-r--r--greybus_usb.patch254
-rw-r--r--greybus_vibrator.patch256
-rw-r--r--series166
33 files changed, 38163 insertions, 57 deletions
diff --git a/greybus_arche.patch b/greybus_arche.patch
new file mode 100644
index 00000000000000..e4222119051d8a
--- /dev/null
+++ b/greybus_arche.patch
@@ -0,0 +1,1404 @@
+---
+ drivers/greybus/arche-apb-ctrl.c | 522 ++++++++++++++++++++++++
+ drivers/greybus/arche-platform.c | 828 +++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/arche_platform.h | 39 +
+ 3 files changed, 1389 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/arche-apb-ctrl.c
+@@ -0,0 +1,522 @@
++/*
++ * Arche Platform driver to control APB.
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/of_gpio.h>
++#include <linux/of_irq.h>
++#include <linux/module.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/regulator/consumer.h>
++#include <linux/spinlock.h>
++#include "arche_platform.h"
++
++
++struct arche_apb_ctrl_drvdata {
++ /* Control GPIO signals to and from AP <=> AP Bridges */
++ int resetn_gpio;
++ int boot_ret_gpio;
++ int pwroff_gpio;
++ int wake_in_gpio;
++ int wake_out_gpio;
++ int pwrdn_gpio;
++
++ enum arche_platform_state state;
++ bool init_disabled;
++
++ struct regulator *vcore;
++ struct regulator *vio;
++
++ int clk_en_gpio;
++ struct clk *clk;
++
++ struct pinctrl *pinctrl;
++ struct pinctrl_state *pin_default;
++
++ /* V2: SPI Bus control */
++ int spi_en_gpio;
++ bool spi_en_polarity_high;
++};
++
++/*
++ * Note that these low level api's are active high
++ */
++static inline void deassert_reset(unsigned int gpio)
++{
++ gpio_set_value(gpio, 1);
++}
++
++static inline void assert_reset(unsigned int gpio)
++{
++ gpio_set_value(gpio, 0);
++}
++
++/*
++ * Note: Please do not modify the below sequence, as it is as per the spec
++ */
++static int coldboot_seq(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev);
++ int ret;
++
++ if (apb->init_disabled ||
++ apb->state == ARCHE_PLATFORM_STATE_ACTIVE)
++ return 0;
++
++ /* Hold APB in reset state */
++ assert_reset(apb->resetn_gpio);
++
++ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
++ gpio_is_valid(apb->spi_en_gpio))
++ devm_gpio_free(dev, apb->spi_en_gpio);
++
++ /* Enable power to APB */
++ if (!IS_ERR(apb->vcore)) {
++ ret = regulator_enable(apb->vcore);
++ if (ret) {
++ dev_err(dev, "failed to enable core regulator\n");
++ return ret;
++ }
++ }
++
++ if (!IS_ERR(apb->vio)) {
++ ret = regulator_enable(apb->vio);
++ if (ret) {
++ dev_err(dev, "failed to enable IO regulator\n");
++ return ret;
++ }
++ }
++
++ apb_bootret_deassert(dev);
++
++ /* On DB3 clock was not mandatory */
++ if (gpio_is_valid(apb->clk_en_gpio))
++ gpio_set_value(apb->clk_en_gpio, 1);
++
++ usleep_range(100, 200);
++
++ /* deassert reset to APB : Active-low signal */
++ deassert_reset(apb->resetn_gpio);
++
++ apb->state = ARCHE_PLATFORM_STATE_ACTIVE;
++
++ return 0;
++}
++
++static int fw_flashing_seq(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev);
++ int ret;
++
++ if (apb->init_disabled ||
++ apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
++ return 0;
++
++ ret = regulator_enable(apb->vcore);
++ if (ret) {
++ dev_err(dev, "failed to enable core regulator\n");
++ return ret;
++ }
++
++ ret = regulator_enable(apb->vio);
++ if (ret) {
++ dev_err(dev, "failed to enable IO regulator\n");
++ return ret;
++ }
++
++ if (gpio_is_valid(apb->spi_en_gpio)) {
++ unsigned long flags;
++
++ if (apb->spi_en_polarity_high)
++ flags = GPIOF_OUT_INIT_HIGH;
++ else
++ flags = GPIOF_OUT_INIT_LOW;
++
++ ret = devm_gpio_request_one(dev, apb->spi_en_gpio,
++ flags, "apb_spi_en");
++ if (ret) {
++ dev_err(dev, "Failed requesting SPI bus en gpio %d\n",
++ apb->spi_en_gpio);
++ return ret;
++ }
++ }
++
++ /* for flashing device should be in reset state */
++ assert_reset(apb->resetn_gpio);
++ apb->state = ARCHE_PLATFORM_STATE_FW_FLASHING;
++
++ return 0;
++}
++
++static int standby_boot_seq(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev);
++
++ if (apb->init_disabled)
++ return 0;
++
++ /* Even if it is in OFF state, then we do not want to change the state */
++ if (apb->state == ARCHE_PLATFORM_STATE_STANDBY ||
++ apb->state == ARCHE_PLATFORM_STATE_OFF)
++ return 0;
++
++ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
++ gpio_is_valid(apb->spi_en_gpio))
++ devm_gpio_free(dev, apb->spi_en_gpio);
++
++ /*
++ * As per WDM spec, do nothing
++ *
++ * Pasted from WDM spec,
++ * - A falling edge on POWEROFF_L is detected (a)
++ * - WDM enters standby mode, but no output signals are changed
++ * */
++
++ /* TODO: POWEROFF_L is input to WDM module */
++ apb->state = ARCHE_PLATFORM_STATE_STANDBY;
++ return 0;
++}
++
++static void poweroff_seq(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev);
++
++ if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_OFF)
++ return;
++
++ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
++ gpio_is_valid(apb->spi_en_gpio))
++ devm_gpio_free(dev, apb->spi_en_gpio);
++
++ /* disable the clock */
++ if (gpio_is_valid(apb->clk_en_gpio))
++ gpio_set_value(apb->clk_en_gpio, 0);
++
++ if (!IS_ERR(apb->vcore) && regulator_is_enabled(apb->vcore) > 0)
++ regulator_disable(apb->vcore);
++
++ if (!IS_ERR(apb->vio) && regulator_is_enabled(apb->vio) > 0)
++ regulator_disable(apb->vio);
++
++ /* As part of exit, put APB back in reset state */
++ assert_reset(apb->resetn_gpio);
++ apb->state = ARCHE_PLATFORM_STATE_OFF;
++
++ /* TODO: May have to send an event to SVC about this exit */
++}
++
++void apb_bootret_assert(struct device *dev)
++{
++ struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev);
++
++ gpio_set_value(apb->boot_ret_gpio, 1);
++}
++
++void apb_bootret_deassert(struct device *dev)
++{
++ struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev);
++
++ gpio_set_value(apb->boot_ret_gpio, 0);
++}
++
++int apb_ctrl_coldboot(struct device *dev)
++{
++ return coldboot_seq(to_platform_device(dev));
++}
++
++int apb_ctrl_fw_flashing(struct device *dev)
++{
++ return fw_flashing_seq(to_platform_device(dev));
++}
++
++int apb_ctrl_standby_boot(struct device *dev)
++{
++ return standby_boot_seq(to_platform_device(dev));
++}
++
++void apb_ctrl_poweroff(struct device *dev)
++{
++ poweroff_seq(to_platform_device(dev));
++}
++
++static ssize_t state_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev);
++ int ret = 0;
++ bool is_disabled;
++
++ if (sysfs_streq(buf, "off")) {
++ if (apb->state == ARCHE_PLATFORM_STATE_OFF)
++ return count;
++
++ poweroff_seq(pdev);
++ } else if (sysfs_streq(buf, "active")) {
++ if (apb->state == ARCHE_PLATFORM_STATE_ACTIVE)
++ return count;
++
++ poweroff_seq(pdev);
++ is_disabled = apb->init_disabled;
++ apb->init_disabled = false;
++ ret = coldboot_seq(pdev);
++ if (ret)
++ apb->init_disabled = is_disabled;
++ } else if (sysfs_streq(buf, "standby")) {
++ if (apb->state == ARCHE_PLATFORM_STATE_STANDBY)
++ return count;
++
++ ret = standby_boot_seq(pdev);
++ } else if (sysfs_streq(buf, "fw_flashing")) {
++ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
++ return count;
++
++ /* First we want to make sure we power off everything
++ * and then enter FW flashing state */
++ poweroff_seq(pdev);
++ ret = fw_flashing_seq(pdev);
++ } else {
++ dev_err(dev, "unknown state\n");
++ ret = -EINVAL;
++ }
++
++ return ret ? ret : count;
++}
++
++static ssize_t state_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev);
++
++ switch (apb->state) {
++ case ARCHE_PLATFORM_STATE_OFF:
++ return sprintf(buf, "off%s\n",
++ apb->init_disabled ? ",disabled" : "");
++ case ARCHE_PLATFORM_STATE_ACTIVE:
++ return sprintf(buf, "active\n");
++ case ARCHE_PLATFORM_STATE_STANDBY:
++ return sprintf(buf, "standby\n");
++ case ARCHE_PLATFORM_STATE_FW_FLASHING:
++ return sprintf(buf, "fw_flashing\n");
++ default:
++ return sprintf(buf, "unknown state\n");
++ }
++}
++
++static DEVICE_ATTR_RW(state);
++
++static int apb_ctrl_get_devtree_data(struct platform_device *pdev,
++ struct arche_apb_ctrl_drvdata *apb)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ int ret;
++
++ apb->resetn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
++ if (apb->resetn_gpio < 0) {
++ dev_err(dev, "failed to get reset gpio\n");
++ return apb->resetn_gpio;
++ }
++ ret = devm_gpio_request_one(dev, apb->resetn_gpio,
++ GPIOF_OUT_INIT_LOW, "apb-reset");
++ if (ret) {
++ dev_err(dev, "Failed requesting reset gpio %d\n",
++ apb->resetn_gpio);
++ return ret;
++ }
++
++ apb->boot_ret_gpio = of_get_named_gpio(np, "boot-ret-gpios", 0);
++ if (apb->boot_ret_gpio < 0) {
++ dev_err(dev, "failed to get boot retention gpio\n");
++ return apb->boot_ret_gpio;
++ }
++ ret = devm_gpio_request_one(dev, apb->boot_ret_gpio,
++ GPIOF_OUT_INIT_LOW, "boot retention");
++ if (ret) {
++ dev_err(dev, "Failed requesting bootret gpio %d\n",
++ apb->boot_ret_gpio);
++ return ret;
++ }
++
++ /* It's not mandatory to support power management interface */
++ apb->pwroff_gpio = of_get_named_gpio(np, "pwr-off-gpios", 0);
++ if (apb->pwroff_gpio < 0) {
++ dev_err(dev, "failed to get power off gpio\n");
++ return apb->pwroff_gpio;
++ }
++ ret = devm_gpio_request_one(dev, apb->pwroff_gpio,
++ GPIOF_IN, "pwroff_n");
++ if (ret) {
++ dev_err(dev, "Failed requesting pwroff_n gpio %d\n",
++ apb->pwroff_gpio);
++ return ret;
++ }
++
++ /* Do not make clock mandatory as of now (for DB3) */
++ apb->clk_en_gpio = of_get_named_gpio(np, "clock-en-gpio", 0);
++ if (apb->clk_en_gpio < 0) {
++ dev_warn(dev, "failed to get clock en gpio\n");
++ } else if (gpio_is_valid(apb->clk_en_gpio)) {
++ ret = devm_gpio_request_one(dev, apb->clk_en_gpio,
++ GPIOF_OUT_INIT_LOW, "apb_clk_en");
++ if (ret) {
++ dev_warn(dev, "Failed requesting APB clock en gpio %d\n",
++ apb->clk_en_gpio);
++ return ret;
++ }
++ }
++
++ apb->pwrdn_gpio = of_get_named_gpio(np, "pwr-down-gpios", 0);
++ if (apb->pwrdn_gpio < 0)
++ dev_warn(dev, "failed to get power down gpio\n");
++
++ /* Regulators are optional, as we may have fixed supply coming in */
++ apb->vcore = devm_regulator_get(dev, "vcore");
++ if (IS_ERR(apb->vcore))
++ dev_warn(dev, "no core regulator found\n");
++
++ apb->vio = devm_regulator_get(dev, "vio");
++ if (IS_ERR(apb->vio))
++ dev_warn(dev, "no IO regulator found\n");
++
++ apb->pinctrl = devm_pinctrl_get(&pdev->dev);
++ if (IS_ERR(apb->pinctrl)) {
++ dev_err(&pdev->dev, "could not get pinctrl handle\n");
++ return PTR_ERR(apb->pinctrl);
++ }
++ apb->pin_default = pinctrl_lookup_state(apb->pinctrl, "default");
++ if (IS_ERR(apb->pin_default)) {
++ dev_err(&pdev->dev, "could not get default pin state\n");
++ return PTR_ERR(apb->pin_default);
++ }
++
++ /* Only applicable for platform >= V2 */
++ apb->spi_en_gpio = of_get_named_gpio(np, "spi-en-gpio", 0);
++ if (apb->spi_en_gpio >= 0) {
++ if (of_property_read_bool(pdev->dev.of_node,
++ "spi-en-active-high"))
++ apb->spi_en_polarity_high = true;
++ }
++
++ return 0;
++}
++
++static int arche_apb_ctrl_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct arche_apb_ctrl_drvdata *apb;
++ struct device *dev = &pdev->dev;
++
++ apb = devm_kzalloc(&pdev->dev, sizeof(*apb), GFP_KERNEL);
++ if (!apb)
++ return -ENOMEM;
++
++ ret = apb_ctrl_get_devtree_data(pdev, apb);
++ if (ret) {
++ dev_err(dev, "failed to get apb devicetree data %d\n", ret);
++ return ret;
++ }
++
++ /* Initially set APB to OFF state */
++ apb->state = ARCHE_PLATFORM_STATE_OFF;
++ /* Check whether device needs to be enabled on boot */
++ if (of_property_read_bool(pdev->dev.of_node, "arche,init-disable"))
++ apb->init_disabled = true;
++
++ platform_set_drvdata(pdev, apb);
++
++ /* Create sysfs interface to allow user to change state dynamically */
++ ret = device_create_file(dev, &dev_attr_state);
++ if (ret) {
++ dev_err(dev, "failed to create state file in sysfs\n");
++ return ret;
++ }
++
++ dev_info(&pdev->dev, "Device registered successfully\n");
++ return 0;
++}
++
++static int arche_apb_ctrl_remove(struct platform_device *pdev)
++{
++ device_remove_file(&pdev->dev, &dev_attr_state);
++ poweroff_seq(pdev);
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static int arche_apb_ctrl_suspend(struct device *dev)
++{
++ /*
++ * If timing profile permits, we may shutdown bridge
++ * completely
++ *
++ * TODO: sequence ??
++ *
++ * Also, need to make sure we meet precondition for unipro suspend
++ * Precondition: Definition ???
++ */
++ return 0;
++}
++
++static int arche_apb_ctrl_resume(struct device *dev)
++{
++ /*
++ * Atleast for ES2 we have to meet the delay requirement between
++ * unipro switch and AP bridge init, depending on whether bridge is in
++ * OFF state or standby state.
++ *
++ * Based on whether bridge is in standby or OFF state we may have to
++ * assert multiple signals. Please refer to WDM spec, for more info.
++ *
++ */
++ return 0;
++}
++
++static void arche_apb_ctrl_shutdown(struct platform_device *pdev)
++{
++ apb_ctrl_poweroff(&pdev->dev);
++}
++
++static SIMPLE_DEV_PM_OPS(arche_apb_ctrl_pm_ops, arche_apb_ctrl_suspend,
++ arche_apb_ctrl_resume);
++
++static struct of_device_id arche_apb_ctrl_of_match[] = {
++ { .compatible = "usbffff,2", },
++ { },
++};
++
++static struct platform_driver arche_apb_ctrl_device_driver = {
++ .probe = arche_apb_ctrl_probe,
++ .remove = arche_apb_ctrl_remove,
++ .shutdown = arche_apb_ctrl_shutdown,
++ .driver = {
++ .name = "arche-apb-ctrl",
++ .pm = &arche_apb_ctrl_pm_ops,
++ .of_match_table = arche_apb_ctrl_of_match,
++ }
++};
++
++int __init arche_apb_init(void)
++{
++ return platform_driver_register(&arche_apb_ctrl_device_driver);
++}
++
++void __exit arche_apb_exit(void)
++{
++ platform_driver_unregister(&arche_apb_ctrl_device_driver);
++}
+--- /dev/null
++++ b/drivers/greybus/arche-platform.c
+@@ -0,0 +1,828 @@
++/*
++ * Arche Platform driver to enable Unipro link.
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_gpio.h>
++#include <linux/of_platform.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/suspend.h>
++#include <linux/time.h>
++#include "arche_platform.h"
++#include "greybus.h"
++
++#include <linux/usb/usb3613.h>
++
++#define WD_COLDBOOT_PULSE_WIDTH_MS 30
++
++enum svc_wakedetect_state {
++ WD_STATE_IDLE, /* Default state = pulled high/low */
++ WD_STATE_BOOT_INIT, /* WD = falling edge (low) */
++ WD_STATE_COLDBOOT_TRIG, /* WD = rising edge (high), > 30msec */
++ WD_STATE_STANDBYBOOT_TRIG, /* As of now not used ?? */
++ WD_STATE_COLDBOOT_START, /* Cold boot process started */
++ WD_STATE_STANDBYBOOT_START, /* Not used */
++ WD_STATE_TIMESYNC,
++};
++
++struct arche_platform_drvdata {
++ /* Control GPIO signals to and from AP <=> SVC */
++ int svc_reset_gpio;
++ bool is_reset_act_hi;
++ int svc_sysboot_gpio;
++ int wake_detect_gpio; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */
++
++ enum arche_platform_state state;
++
++ int svc_refclk_req;
++ struct clk *svc_ref_clk;
++
++ struct pinctrl *pinctrl;
++ struct pinctrl_state *pin_default;
++
++ int num_apbs;
++
++ enum svc_wakedetect_state wake_detect_state;
++ int wake_detect_irq;
++ spinlock_t wake_lock; /* Protect wake_detect_state */
++ struct mutex platform_state_mutex; /* Protect state */
++ wait_queue_head_t wq; /* WQ for arche_pdata->state */
++ unsigned long wake_detect_start;
++ struct notifier_block pm_notifier;
++
++ struct device *dev;
++ struct gb_timesync_svc *timesync_svc_pdata;
++};
++
++static int arche_apb_bootret_assert(struct device *dev, void *data)
++{
++ apb_bootret_assert(dev);
++ return 0;
++}
++
++static int arche_apb_bootret_deassert(struct device *dev, void *data)
++{
++ apb_bootret_deassert(dev);
++ return 0;
++}
++
++/* Requires calling context to hold arche_pdata->platform_state_mutex */
++static void arche_platform_set_state(struct arche_platform_drvdata *arche_pdata,
++ enum arche_platform_state state)
++{
++ arche_pdata->state = state;
++}
++
++/*
++ * arche_platform_change_state: Change the operational state
++ *
++ * This exported function allows external drivers to change the state
++ * of the arche-platform driver.
++ * Note that this function only supports transitions between two states
++ * with limited functionality.
++ *
++ * - ARCHE_PLATFORM_STATE_TIME_SYNC:
++ * Once set, allows timesync operations between SVC <=> AP and makes
++ * sure that arche-platform driver ignores any subsequent events/pulses
++ * from SVC over wake/detect.
++ *
++ * - ARCHE_PLATFORM_STATE_ACTIVE:
++ * Puts back driver to active state, where any pulse from SVC on wake/detect
++ * line would trigger either cold/standby boot.
++ * Note: Transition request from this function does not trigger cold/standby
++ * boot. It just puts back driver book keeping variable back to ACTIVE
++ * state and restores the interrupt.
++ *
++ * Returns -ENODEV if device not found, -EAGAIN if the driver cannot currently
++ * satisfy the requested state-transition or -EINVAL for all other
++ * state-transition requests.
++ */
++int arche_platform_change_state(enum arche_platform_state state,
++ struct gb_timesync_svc *timesync_svc_pdata)
++{
++ struct arche_platform_drvdata *arche_pdata;
++ struct platform_device *pdev;
++ struct device_node *np;
++ int ret = -EAGAIN;
++ unsigned long flags;
++
++ np = of_find_compatible_node(NULL, NULL, "google,arche-platform");
++ if (!np) {
++ pr_err("google,arche-platform device node not found\n");
++ return -ENODEV;
++ }
++
++ pdev = of_find_device_by_node(np);
++ if (!pdev) {
++ pr_err("arche-platform device not found\n");
++ return -ENODEV;
++ }
++
++ arche_pdata = platform_get_drvdata(pdev);
++
++ mutex_lock(&arche_pdata->platform_state_mutex);
++ spin_lock_irqsave(&arche_pdata->wake_lock, flags);
++
++ if (arche_pdata->state == state) {
++ ret = 0;
++ goto exit;
++ }
++
++ switch (state) {
++ case ARCHE_PLATFORM_STATE_TIME_SYNC:
++ if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
++ ret = -EINVAL;
++ goto exit;
++ }
++ if (arche_pdata->wake_detect_state != WD_STATE_IDLE) {
++ dev_err(arche_pdata->dev,
++ "driver busy with wake/detect line ops\n");
++ goto exit;
++ }
++ device_for_each_child(arche_pdata->dev, NULL,
++ arche_apb_bootret_assert);
++ arche_pdata->wake_detect_state = WD_STATE_TIMESYNC;
++ break;
++ case ARCHE_PLATFORM_STATE_ACTIVE:
++ if (arche_pdata->state != ARCHE_PLATFORM_STATE_TIME_SYNC) {
++ ret = -EINVAL;
++ goto exit;
++ }
++ device_for_each_child(arche_pdata->dev, NULL,
++ arche_apb_bootret_deassert);
++ arche_pdata->wake_detect_state = WD_STATE_IDLE;
++ break;
++ case ARCHE_PLATFORM_STATE_OFF:
++ case ARCHE_PLATFORM_STATE_STANDBY:
++ case ARCHE_PLATFORM_STATE_FW_FLASHING:
++ dev_err(arche_pdata->dev, "busy, request to retry later\n");
++ goto exit;
++ default:
++ ret = -EINVAL;
++ dev_err(arche_pdata->dev,
++ "invalid state transition request\n");
++ goto exit;
++ }
++ arche_pdata->timesync_svc_pdata = timesync_svc_pdata;
++ arche_platform_set_state(arche_pdata, state);
++ if (state == ARCHE_PLATFORM_STATE_ACTIVE)
++ wake_up(&arche_pdata->wq);
++
++ ret = 0;
++exit:
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++ of_node_put(np);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(arche_platform_change_state);
++
++/* Requires arche_pdata->wake_lock is held by calling context */
++static void arche_platform_set_wake_detect_state(
++ struct arche_platform_drvdata *arche_pdata,
++ enum svc_wakedetect_state state)
++{
++ arche_pdata->wake_detect_state = state;
++}
++
++static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
++{
++ gpio_set_value(gpio, onoff);
++}
++
++static int apb_cold_boot(struct device *dev, void *data)
++{
++ int ret;
++
++ ret = apb_ctrl_coldboot(dev);
++ if (ret)
++ dev_warn(dev, "failed to coldboot\n");
++
++ /*Child nodes are independent, so do not exit coldboot operation */
++ return 0;
++}
++
++static int apb_poweroff(struct device *dev, void *data)
++{
++ apb_ctrl_poweroff(dev);
++
++ /* Enable HUB3613 into HUB mode. */
++ if (usb3613_hub_mode_ctrl(false))
++ dev_warn(dev, "failed to control hub device\n");
++
++ return 0;
++}
++
++static void arche_platform_wd_irq_en(struct arche_platform_drvdata *arche_pdata)
++{
++ /* Enable interrupt here, to read event back from SVC */
++ gpio_direction_input(arche_pdata->wake_detect_gpio);
++ enable_irq(arche_pdata->wake_detect_irq);
++}
++
++static irqreturn_t arche_platform_wd_irq_thread(int irq, void *devid)
++{
++ struct arche_platform_drvdata *arche_pdata = devid;
++ unsigned long flags;
++
++ spin_lock_irqsave(&arche_pdata->wake_lock, flags);
++ if (arche_pdata->wake_detect_state != WD_STATE_COLDBOOT_TRIG) {
++ /* Something is wrong */
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++ return IRQ_HANDLED;
++ }
++
++ arche_platform_set_wake_detect_state(arche_pdata,
++ WD_STATE_COLDBOOT_START);
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++
++ /* It should complete power cycle, so first make sure it is poweroff */
++ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
++
++ /* Bring APB out of reset: cold boot sequence */
++ device_for_each_child(arche_pdata->dev, NULL, apb_cold_boot);
++
++ /* Enable HUB3613 into HUB mode. */
++ if (usb3613_hub_mode_ctrl(true))
++ dev_warn(arche_pdata->dev, "failed to control hub device\n");
++
++ spin_lock_irqsave(&arche_pdata->wake_lock, flags);
++ arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t arche_platform_wd_irq(int irq, void *devid)
++{
++ struct arche_platform_drvdata *arche_pdata = devid;
++ unsigned long flags;
++
++ spin_lock_irqsave(&arche_pdata->wake_lock, flags);
++
++ if (arche_pdata->wake_detect_state == WD_STATE_TIMESYNC) {
++ gb_timesync_irq(arche_pdata->timesync_svc_pdata);
++ goto exit;
++ }
++
++ if (gpio_get_value(arche_pdata->wake_detect_gpio)) {
++ /* wake/detect rising */
++
++ /*
++ * If wake/detect line goes high after low, within less than
++ * 30msec, then standby boot sequence is initiated, which is not
++ * supported/implemented as of now. So ignore it.
++ */
++ if (arche_pdata->wake_detect_state == WD_STATE_BOOT_INIT) {
++ if (time_before(jiffies,
++ arche_pdata->wake_detect_start +
++ msecs_to_jiffies(WD_COLDBOOT_PULSE_WIDTH_MS))) {
++ arche_platform_set_wake_detect_state(arche_pdata,
++ WD_STATE_IDLE);
++ } else {
++ /* Check we are not in middle of irq thread already */
++ if (arche_pdata->wake_detect_state !=
++ WD_STATE_COLDBOOT_START) {
++ arche_platform_set_wake_detect_state(arche_pdata,
++ WD_STATE_COLDBOOT_TRIG);
++ spin_unlock_irqrestore(
++ &arche_pdata->wake_lock,
++ flags);
++ return IRQ_WAKE_THREAD;
++ }
++ }
++ }
++ } else {
++ /* wake/detect falling */
++ if (arche_pdata->wake_detect_state == WD_STATE_IDLE) {
++ arche_pdata->wake_detect_start = jiffies;
++ /*
++ * In the begining, when wake/detect goes low (first time), we assume
++ * it is meant for coldboot and set the flag. If wake/detect line stays low
++ * beyond 30msec, then it is coldboot else fallback to standby boot.
++ */
++ arche_platform_set_wake_detect_state(arche_pdata,
++ WD_STATE_BOOT_INIT);
++ }
++ }
++
++exit:
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Requires arche_pdata->platform_state_mutex to be held
++ */
++static int arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
++{
++ int ret;
++
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
++ return 0;
++
++ dev_info(arche_pdata->dev, "Booting from cold boot state\n");
++
++ svc_reset_onoff(arche_pdata->svc_reset_gpio,
++ arche_pdata->is_reset_act_hi);
++
++ gpio_set_value(arche_pdata->svc_sysboot_gpio, 0);
++ usleep_range(100, 200);
++
++ ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
++ if (ret) {
++ dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
++ ret);
++ return ret;
++ }
++
++ /* bring SVC out of reset */
++ svc_reset_onoff(arche_pdata->svc_reset_gpio,
++ !arche_pdata->is_reset_act_hi);
++
++ arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_ACTIVE);
++
++ return 0;
++}
++
++/*
++ * Requires arche_pdata->platform_state_mutex to be held
++ */
++static int arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
++{
++ int ret;
++
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
++ return 0;
++
++ dev_info(arche_pdata->dev, "Switching to FW flashing state\n");
++
++ svc_reset_onoff(arche_pdata->svc_reset_gpio,
++ arche_pdata->is_reset_act_hi);
++
++ gpio_set_value(arche_pdata->svc_sysboot_gpio, 1);
++
++ usleep_range(100, 200);
++
++ ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
++ if (ret) {
++ dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
++ ret);
++ return ret;
++ }
++
++ svc_reset_onoff(arche_pdata->svc_reset_gpio,
++ !arche_pdata->is_reset_act_hi);
++
++ arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_FW_FLASHING);
++
++ return 0;
++}
++
++/*
++ * Requires arche_pdata->platform_state_mutex to be held
++ */
++static void arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata)
++{
++ unsigned long flags;
++
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
++ return;
++
++ /* If in fw_flashing mode, then no need to repeate things again */
++ if (arche_pdata->state != ARCHE_PLATFORM_STATE_FW_FLASHING) {
++ disable_irq(arche_pdata->wake_detect_irq);
++
++ spin_lock_irqsave(&arche_pdata->wake_lock, flags);
++ arche_platform_set_wake_detect_state(arche_pdata,
++ WD_STATE_IDLE);
++ spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
++ }
++
++ clk_disable_unprepare(arche_pdata->svc_ref_clk);
++
++ /* As part of exit, put APB back in reset state */
++ svc_reset_onoff(arche_pdata->svc_reset_gpio,
++ arche_pdata->is_reset_act_hi);
++
++ arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
++}
++
++static ssize_t state_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
++ int ret = 0;
++
++retry:
++ mutex_lock(&arche_pdata->platform_state_mutex);
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_TIME_SYNC) {
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++ ret = wait_event_interruptible(
++ arche_pdata->wq,
++ arche_pdata->state != ARCHE_PLATFORM_STATE_TIME_SYNC);
++ if (ret)
++ return ret;
++ goto retry;
++ }
++
++ if (sysfs_streq(buf, "off")) {
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
++ goto exit;
++
++ /* If SVC goes down, bring down APB's as well */
++ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
++
++ arche_platform_poweroff_seq(arche_pdata);
++
++ } else if (sysfs_streq(buf, "active")) {
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
++ goto exit;
++
++ /* First we want to make sure we power off everything
++ * and then activate back again */
++ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
++ arche_platform_poweroff_seq(arche_pdata);
++
++ arche_platform_wd_irq_en(arche_pdata);
++ ret = arche_platform_coldboot_seq(arche_pdata);
++ if (ret)
++ goto exit;
++
++ } else if (sysfs_streq(buf, "standby")) {
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY)
++ goto exit;
++
++ dev_warn(arche_pdata->dev, "standby state not supported\n");
++ } else if (sysfs_streq(buf, "fw_flashing")) {
++ if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
++ goto exit;
++
++ /*
++ * Here we only control SVC.
++ *
++ * In case of FW_FLASHING mode we do not want to control
++ * APBs, as in case of V2, SPI bus is shared between both
++ * the APBs. So let user chose which APB he wants to flash.
++ */
++ arche_platform_poweroff_seq(arche_pdata);
++
++ ret = arche_platform_fw_flashing_seq(arche_pdata);
++ if (ret)
++ goto exit;
++ } else {
++ dev_err(arche_pdata->dev, "unknown state\n");
++ ret = -EINVAL;
++ }
++
++exit:
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++ return ret ? ret : count;
++}
++
++static ssize_t state_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct arche_platform_drvdata *arche_pdata = dev_get_drvdata(dev);
++
++ switch (arche_pdata->state) {
++ case ARCHE_PLATFORM_STATE_OFF:
++ return sprintf(buf, "off\n");
++ case ARCHE_PLATFORM_STATE_ACTIVE:
++ return sprintf(buf, "active\n");
++ case ARCHE_PLATFORM_STATE_STANDBY:
++ return sprintf(buf, "standby\n");
++ case ARCHE_PLATFORM_STATE_FW_FLASHING:
++ return sprintf(buf, "fw_flashing\n");
++ case ARCHE_PLATFORM_STATE_TIME_SYNC:
++ return sprintf(buf, "time_sync\n");
++ default:
++ return sprintf(buf, "unknown state\n");
++ }
++}
++
++static DEVICE_ATTR_RW(state);
++
++static int arche_platform_pm_notifier(struct notifier_block *notifier,
++ unsigned long pm_event, void *unused)
++{
++ struct arche_platform_drvdata *arche_pdata =
++ container_of(notifier, struct arche_platform_drvdata,
++ pm_notifier);
++ int ret = NOTIFY_DONE;
++
++ mutex_lock(&arche_pdata->platform_state_mutex);
++ switch (pm_event) {
++ case PM_SUSPEND_PREPARE:
++ if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
++ ret = NOTIFY_STOP;
++ break;
++ }
++ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
++ arche_platform_poweroff_seq(arche_pdata);
++ break;
++ case PM_POST_SUSPEND:
++ if (arche_pdata->state != ARCHE_PLATFORM_STATE_OFF)
++ break;
++
++ arche_platform_wd_irq_en(arche_pdata);
++ arche_platform_coldboot_seq(arche_pdata);
++ break;
++ default:
++ break;
++ }
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++
++ return ret;
++}
++
++static int arche_platform_probe(struct platform_device *pdev)
++{
++ struct arche_platform_drvdata *arche_pdata;
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ int ret;
++
++ arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata), GFP_KERNEL);
++ if (!arche_pdata)
++ return -ENOMEM;
++
++ /* setup svc reset gpio */
++ arche_pdata->is_reset_act_hi = of_property_read_bool(np,
++ "svc,reset-active-high");
++ arche_pdata->svc_reset_gpio = of_get_named_gpio(np, "svc,reset-gpio", 0);
++ if (arche_pdata->svc_reset_gpio < 0) {
++ dev_err(dev, "failed to get reset-gpio\n");
++ return arche_pdata->svc_reset_gpio;
++ }
++ ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset");
++ if (ret) {
++ dev_err(dev, "failed to request svc-reset gpio:%d\n", ret);
++ return ret;
++ }
++ ret = gpio_direction_output(arche_pdata->svc_reset_gpio,
++ arche_pdata->is_reset_act_hi);
++ if (ret) {
++ dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
++ return ret;
++ }
++ arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
++
++ arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np,
++ "svc,sysboot-gpio", 0);
++ if (arche_pdata->svc_sysboot_gpio < 0) {
++ dev_err(dev, "failed to get sysboot gpio\n");
++ return arche_pdata->svc_sysboot_gpio;
++ }
++ ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0");
++ if (ret) {
++ dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret);
++ return ret;
++ }
++ ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0);
++ if (ret) {
++ dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
++ return ret;
++ }
++
++ /* setup the clock request gpio first */
++ arche_pdata->svc_refclk_req = of_get_named_gpio(np,
++ "svc,refclk-req-gpio", 0);
++ if (arche_pdata->svc_refclk_req < 0) {
++ dev_err(dev, "failed to get svc clock-req gpio\n");
++ return arche_pdata->svc_refclk_req;
++ }
++ ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req, "svc-clk-req");
++ if (ret) {
++ dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret);
++ return ret;
++ }
++ ret = gpio_direction_input(arche_pdata->svc_refclk_req);
++ if (ret) {
++ dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret);
++ return ret;
++ }
++
++ /* setup refclk2 to follow the pin */
++ arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk");
++ if (IS_ERR(arche_pdata->svc_ref_clk)) {
++ ret = PTR_ERR(arche_pdata->svc_ref_clk);
++ dev_err(dev, "failed to get svc_ref_clk: %d\n", ret);
++ return ret;
++ }
++
++ platform_set_drvdata(pdev, arche_pdata);
++
++ arche_pdata->num_apbs = of_get_child_count(np);
++ dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
++
++ arche_pdata->wake_detect_gpio = of_get_named_gpio(np, "svc,wake-detect-gpio", 0);
++ if (arche_pdata->wake_detect_gpio < 0) {
++ dev_err(dev, "failed to get wake detect gpio\n");
++ ret = arche_pdata->wake_detect_gpio;
++ return ret;
++ }
++
++ ret = devm_gpio_request(dev, arche_pdata->wake_detect_gpio, "wake detect");
++ if (ret) {
++ dev_err(dev, "Failed requesting wake_detect gpio %d\n",
++ arche_pdata->wake_detect_gpio);
++ return ret;
++ }
++
++ arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
++
++ arche_pdata->dev = &pdev->dev;
++
++ spin_lock_init(&arche_pdata->wake_lock);
++ mutex_init(&arche_pdata->platform_state_mutex);
++ init_waitqueue_head(&arche_pdata->wq);
++ arche_pdata->wake_detect_irq =
++ gpio_to_irq(arche_pdata->wake_detect_gpio);
++
++ ret = devm_request_threaded_irq(dev, arche_pdata->wake_detect_irq,
++ arche_platform_wd_irq,
++ arche_platform_wd_irq_thread,
++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
++ dev_name(dev), arche_pdata);
++ if (ret) {
++ dev_err(dev, "failed to request wake detect IRQ %d\n", ret);
++ return ret;
++ }
++ disable_irq(arche_pdata->wake_detect_irq);
++
++ ret = device_create_file(dev, &dev_attr_state);
++ if (ret) {
++ dev_err(dev, "failed to create state file in sysfs\n");
++ return ret;
++ }
++
++ ret = of_platform_populate(np, NULL, NULL, dev);
++ if (ret) {
++ dev_err(dev, "failed to populate child nodes %d\n", ret);
++ goto err_device_remove;
++ }
++
++ arche_pdata->pm_notifier.notifier_call = arche_platform_pm_notifier;
++ ret = register_pm_notifier(&arche_pdata->pm_notifier);
++
++ if (ret) {
++ dev_err(dev, "failed to register pm notifier %d\n", ret);
++ goto err_device_remove;
++ }
++
++ /* Register callback pointer */
++ arche_platform_change_state_cb = arche_platform_change_state;
++
++ /* Explicitly power off if requested */
++ if (!of_property_read_bool(pdev->dev.of_node, "arche,init-off")) {
++ mutex_lock(&arche_pdata->platform_state_mutex);
++ ret = arche_platform_coldboot_seq(arche_pdata);
++ if (ret) {
++ dev_err(dev, "Failed to cold boot svc %d\n", ret);
++ goto err_coldboot;
++ }
++ arche_platform_wd_irq_en(arche_pdata);
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++ }
++
++ dev_info(dev, "Device registered successfully\n");
++ return 0;
++
++err_coldboot:
++ mutex_unlock(&arche_pdata->platform_state_mutex);
++err_device_remove:
++ device_remove_file(&pdev->dev, &dev_attr_state);
++ return ret;
++}
++
++static int arche_remove_child(struct device *dev, void *unused)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++
++ platform_device_unregister(pdev);
++
++ return 0;
++}
++
++static int arche_platform_remove(struct platform_device *pdev)
++{
++ struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
++
++ unregister_pm_notifier(&arche_pdata->pm_notifier);
++ device_remove_file(&pdev->dev, &dev_attr_state);
++ device_for_each_child(&pdev->dev, NULL, arche_remove_child);
++ arche_platform_poweroff_seq(arche_pdata);
++ platform_set_drvdata(pdev, NULL);
++
++ if (usb3613_hub_mode_ctrl(false))
++ dev_warn(arche_pdata->dev, "failed to control hub device\n");
++ /* TODO: Should we do anything more here ?? */
++ return 0;
++}
++
++static int arche_platform_suspend(struct device *dev)
++{
++ /*
++ * If timing profile premits, we may shutdown bridge
++ * completely
++ *
++ * TODO: sequence ??
++ *
++ * Also, need to make sure we meet precondition for unipro suspend
++ * Precondition: Definition ???
++ */
++ return 0;
++}
++
++static int arche_platform_resume(struct device *dev)
++{
++ /*
++ * Atleast for ES2 we have to meet the delay requirement between
++ * unipro switch and AP bridge init, depending on whether bridge is in
++ * OFF state or standby state.
++ *
++ * Based on whether bridge is in standby or OFF state we may have to
++ * assert multiple signals. Please refer to WDM spec, for more info.
++ *
++ */
++ return 0;
++}
++
++static void arche_platform_shutdown(struct platform_device *pdev)
++{
++ struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
++
++ arche_platform_poweroff_seq(arche_pdata);
++
++ usb3613_hub_mode_ctrl(false);
++}
++
++static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
++ arche_platform_suspend,
++ arche_platform_resume);
++
++static struct of_device_id arche_platform_of_match[] = {
++ { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
++ { },
++};
++
++static struct of_device_id arche_combined_id[] = {
++ { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
++ { .compatible = "usbffff,2", },
++ { },
++};
++MODULE_DEVICE_TABLE(of, arche_combined_id);
++
++static struct platform_driver arche_platform_device_driver = {
++ .probe = arche_platform_probe,
++ .remove = arche_platform_remove,
++ .shutdown = arche_platform_shutdown,
++ .driver = {
++ .name = "arche-platform-ctrl",
++ .pm = &arche_platform_pm_ops,
++ .of_match_table = arche_platform_of_match,
++ }
++};
++
++static int __init arche_init(void)
++{
++ int retval;
++
++ retval = platform_driver_register(&arche_platform_device_driver);
++ if (retval)
++ return retval;
++
++ retval = arche_apb_init();
++ if (retval)
++ platform_driver_unregister(&arche_platform_device_driver);
++
++ return retval;
++}
++module_init(arche_init);
++
++static void __exit arche_exit(void)
++{
++ arche_apb_exit();
++ platform_driver_unregister(&arche_platform_device_driver);
++}
++module_exit(arche_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>");
++MODULE_DESCRIPTION("Arche Platform Driver");
+--- /dev/null
++++ b/drivers/greybus/arche_platform.h
+@@ -0,0 +1,39 @@
++/*
++ * Arche Platform driver to enable Unipro link.
++ *
++ * Copyright 2015-2016 Google Inc.
++ * Copyright 2015-2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __ARCHE_PLATFORM_H
++#define __ARCHE_PLATFORM_H
++
++#include "timesync.h"
++
++enum arche_platform_state {
++ ARCHE_PLATFORM_STATE_OFF,
++ ARCHE_PLATFORM_STATE_ACTIVE,
++ ARCHE_PLATFORM_STATE_STANDBY,
++ ARCHE_PLATFORM_STATE_FW_FLASHING,
++ ARCHE_PLATFORM_STATE_TIME_SYNC,
++};
++
++int arche_platform_change_state(enum arche_platform_state state,
++ struct gb_timesync_svc *pdata);
++
++extern int (*arche_platform_change_state_cb)(enum arche_platform_state state,
++ struct gb_timesync_svc *pdata);
++int __init arche_apb_init(void);
++void __exit arche_apb_exit(void);
++
++/* Operational states for the APB device */
++int apb_ctrl_coldboot(struct device *dev);
++int apb_ctrl_fw_flashing(struct device *dev);
++int apb_ctrl_standby_boot(struct device *dev);
++void apb_ctrl_poweroff(struct device *dev);
++void apb_bootret_assert(struct device *dev);
++void apb_bootret_deassert(struct device *dev);
++
++#endif /* __ARCHE_PLATFORM_H */
diff --git a/greybus_audio.patch b/greybus_audio.patch
new file mode 100644
index 00000000000000..0fa4ec2f8b46c8
--- /dev/null
+++ b/greybus_audio.patch
@@ -0,0 +1,4636 @@
+---
+ drivers/greybus/audio_apbridgea.c | 207 ++++
+ drivers/greybus/audio_apbridgea.h | 156 +++
+ drivers/greybus/audio_codec.c | 1132 +++++++++++++++++++++++++
+ drivers/greybus/audio_codec.h | 283 ++++++
+ drivers/greybus/audio_gb.c | 228 +++++
+ drivers/greybus/audio_manager.c | 184 ++++
+ drivers/greybus/audio_manager.h | 83 +
+ drivers/greybus/audio_manager_module.c | 258 +++++
+ drivers/greybus/audio_manager_private.h | 28
+ drivers/greybus/audio_manager_sysfs.c | 102 ++
+ drivers/greybus/audio_module.c | 482 ++++++++++
+ drivers/greybus/audio_topology.c | 1442 ++++++++++++++++++++++++++++++++
+ 12 files changed, 4585 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/audio_apbridgea.c
+@@ -0,0 +1,207 @@
++/*
++ * Greybus Audio Device Class Protocol helpers
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++#include "greybus_protocols.h"
++#include "audio_apbridgea.h"
++#include "audio_codec.h"
++
++int gb_audio_apbridgea_set_config(struct gb_connection *connection,
++ __u16 i2s_port, __u32 format, __u32 rate,
++ __u32 mclk_freq)
++{
++ struct audio_apbridgea_set_config_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_CONFIG;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.format = cpu_to_le32(format);
++ req.rate = cpu_to_le32(rate);
++ req.mclk_freq = cpu_to_le32(mclk_freq);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_config);
++
++int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
++ __u16 i2s_port, __u16 cportid,
++ __u8 direction)
++{
++ struct audio_apbridgea_register_cport_request req;
++ int ret;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.cport = cpu_to_le16(cportid);
++ req.direction = direction;
++
++ ret = gb_pm_runtime_get_sync(connection->bundle);
++ if (ret)
++ return ret;
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_register_cport);
++
++int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
++ __u16 i2s_port, __u16 cportid,
++ __u8 direction)
++{
++ struct audio_apbridgea_unregister_cport_request req;
++ int ret;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.cport = cpu_to_le16(cportid);
++ req.direction = direction;
++
++ ret = gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++
++ gb_pm_runtime_put_autosuspend(connection->bundle);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_unregister_cport);
++
++int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection,
++ __u16 i2s_port, __u16 size)
++{
++ struct audio_apbridgea_set_tx_data_size_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.size = cpu_to_le16(size);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_tx_data_size);
++
++int gb_audio_apbridgea_prepare_tx(struct gb_connection *connection,
++ __u16 i2s_port)
++{
++ struct audio_apbridgea_prepare_tx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_TX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_tx);
++
++int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
++ __u16 i2s_port, __u64 timestamp)
++{
++ struct audio_apbridgea_start_tx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_TX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.timestamp = cpu_to_le64(timestamp);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_start_tx);
++
++int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port)
++{
++ struct audio_apbridgea_stop_tx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_TX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_tx);
++
++int gb_audio_apbridgea_shutdown_tx(struct gb_connection *connection,
++ __u16 i2s_port)
++{
++ struct audio_apbridgea_shutdown_tx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_tx);
++
++int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
++ __u16 i2s_port, __u16 size)
++{
++ struct audio_apbridgea_set_rx_data_size_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++ req.size = cpu_to_le16(size);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_rx_data_size);
++
++int gb_audio_apbridgea_prepare_rx(struct gb_connection *connection,
++ __u16 i2s_port)
++{
++ struct audio_apbridgea_prepare_rx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_RX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_rx);
++
++int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
++ __u16 i2s_port)
++{
++ struct audio_apbridgea_start_rx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_RX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_start_rx);
++
++int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, __u16 i2s_port)
++{
++ struct audio_apbridgea_stop_rx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_RX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_rx);
++
++int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection,
++ __u16 i2s_port)
++{
++ struct audio_apbridgea_shutdown_rx_request req;
++
++ req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_RX;
++ req.hdr.i2s_port = cpu_to_le16(i2s_port);
++
++ return gb_hd_output(connection->hd, &req, sizeof(req),
++ GB_APB_REQUEST_AUDIO_CONTROL, true);
++}
++EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_rx);
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("greybus:audio-apbridgea");
++MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library");
++MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
+--- /dev/null
++++ b/drivers/greybus/audio_apbridgea.h
+@@ -0,0 +1,156 @@
++/**
++ * Copyright (c) 2015-2016 Google Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * 1. Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright notice,
++ * this list of conditions and the following disclaimer in the documentation
++ * and/or other materials provided with the distribution.
++ * 3. Neither the name of the copyright holder nor the names of its
++ * contributors may be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++/*
++ * This is a special protocol for configuring communication over the
++ * I2S bus between the DSP on the MSM8994 and APBridgeA. Therefore,
++ * we can predefine several low-level attributes of the communication
++ * because we know that they are supported. In particular, the following
++ * assumptions are made:
++ * - there are two channels (i.e., stereo)
++ * - the low-level protocol is I2S as defined by Philips/NXP
++ * - the DSP on the MSM8994 is the clock master for MCLK, BCLK, and WCLK
++ * - WCLK changes on the falling edge of BCLK
++ * - WCLK low for left channel; high for right channel
++ * - TX data is sent on the falling edge of BCLK
++ * - RX data is received/latched on the rising edge of BCLK
++ */
++
++#ifndef __AUDIO_APBRIDGEA_H
++#define __AUDIO_APBRIDGEA_H
++
++#define AUDIO_APBRIDGEA_TYPE_SET_CONFIG 0x01
++#define AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT 0x02
++#define AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT 0x03
++#define AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE 0x04
++ /* 0x05 unused */
++#define AUDIO_APBRIDGEA_TYPE_PREPARE_TX 0x06
++#define AUDIO_APBRIDGEA_TYPE_START_TX 0x07
++#define AUDIO_APBRIDGEA_TYPE_STOP_TX 0x08
++#define AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX 0x09
++#define AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE 0x0a
++ /* 0x0b unused */
++#define AUDIO_APBRIDGEA_TYPE_PREPARE_RX 0x0c
++#define AUDIO_APBRIDGEA_TYPE_START_RX 0x0d
++#define AUDIO_APBRIDGEA_TYPE_STOP_RX 0x0e
++#define AUDIO_APBRIDGEA_TYPE_SHUTDOWN_RX 0x0f
++
++#define AUDIO_APBRIDGEA_PCM_FMT_8 BIT(0)
++#define AUDIO_APBRIDGEA_PCM_FMT_16 BIT(1)
++#define AUDIO_APBRIDGEA_PCM_FMT_24 BIT(2)
++#define AUDIO_APBRIDGEA_PCM_FMT_32 BIT(3)
++#define AUDIO_APBRIDGEA_PCM_FMT_64 BIT(4)
++
++#define AUDIO_APBRIDGEA_PCM_RATE_5512 BIT(0)
++#define AUDIO_APBRIDGEA_PCM_RATE_8000 BIT(1)
++#define AUDIO_APBRIDGEA_PCM_RATE_11025 BIT(2)
++#define AUDIO_APBRIDGEA_PCM_RATE_16000 BIT(3)
++#define AUDIO_APBRIDGEA_PCM_RATE_22050 BIT(4)
++#define AUDIO_APBRIDGEA_PCM_RATE_32000 BIT(5)
++#define AUDIO_APBRIDGEA_PCM_RATE_44100 BIT(6)
++#define AUDIO_APBRIDGEA_PCM_RATE_48000 BIT(7)
++#define AUDIO_APBRIDGEA_PCM_RATE_64000 BIT(8)
++#define AUDIO_APBRIDGEA_PCM_RATE_88200 BIT(9)
++#define AUDIO_APBRIDGEA_PCM_RATE_96000 BIT(10)
++#define AUDIO_APBRIDGEA_PCM_RATE_176400 BIT(11)
++#define AUDIO_APBRIDGEA_PCM_RATE_192000 BIT(12)
++
++#define AUDIO_APBRIDGEA_DIRECTION_TX BIT(0)
++#define AUDIO_APBRIDGEA_DIRECTION_RX BIT(1)
++
++/* The I2S port is passed in the 'index' parameter of the USB request */
++/* The CPort is passed in the 'value' parameter of the USB request */
++
++struct audio_apbridgea_hdr {
++ __u8 type;
++ __le16 i2s_port;
++ __u8 data[0];
++} __packed;
++
++struct audio_apbridgea_set_config_request {
++ struct audio_apbridgea_hdr hdr;
++ __le32 format; /* AUDIO_APBRIDGEA_PCM_FMT_* */
++ __le32 rate; /* AUDIO_APBRIDGEA_PCM_RATE_* */
++ __le32 mclk_freq; /* XXX Remove? */
++} __packed;
++
++struct audio_apbridgea_register_cport_request {
++ struct audio_apbridgea_hdr hdr;
++ __le16 cport;
++ __u8 direction;
++} __packed;
++
++struct audio_apbridgea_unregister_cport_request {
++ struct audio_apbridgea_hdr hdr;
++ __le16 cport;
++ __u8 direction;
++} __packed;
++
++struct audio_apbridgea_set_tx_data_size_request {
++ struct audio_apbridgea_hdr hdr;
++ __le16 size;
++} __packed;
++
++struct audio_apbridgea_prepare_tx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_start_tx_request {
++ struct audio_apbridgea_hdr hdr;
++ __le64 timestamp;
++} __packed;
++
++struct audio_apbridgea_stop_tx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_shutdown_tx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_set_rx_data_size_request {
++ struct audio_apbridgea_hdr hdr;
++ __le16 size;
++} __packed;
++
++struct audio_apbridgea_prepare_rx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_start_rx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_stop_rx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++struct audio_apbridgea_shutdown_rx_request {
++ struct audio_apbridgea_hdr hdr;
++} __packed;
++
++#endif /*__AUDIO_APBRIDGEA_H */
+--- /dev/null
++++ b/drivers/greybus/audio_codec.c
+@@ -0,0 +1,1132 @@
++/*
++ * APBridge ALSA SoC dummy codec driver
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <sound/soc.h>
++#include <sound/pcm_params.h>
++#include <uapi/linux/input.h>
++
++#include "audio_codec.h"
++#include "audio_apbridgea.h"
++#include "audio_manager.h"
++
++static struct gbaudio_codec_info *gbcodec;
++
++static struct gbaudio_data_connection *
++find_data(struct gbaudio_module_info *module, int id)
++{
++ struct gbaudio_data_connection *data;
++
++ list_for_each_entry(data, &module->data_list, list) {
++ if (id == data->id)
++ return data;
++ }
++ return NULL;
++}
++
++static struct gbaudio_stream_params *
++find_dai_stream_params(struct gbaudio_codec_info *codec, int id, int stream)
++{
++ struct gbaudio_codec_dai *dai;
++
++ list_for_each_entry(dai, &codec->dai_list, list) {
++ if (dai->id == id)
++ return &dai->params[stream];
++ }
++ return NULL;
++}
++
++static int gbaudio_module_enable_tx(struct gbaudio_codec_info *codec,
++ struct gbaudio_module_info *module, int id)
++{
++ int module_state, ret = 0;
++ uint16_t data_cport, i2s_port, cportid;
++ uint8_t sig_bits, channels;
++ uint32_t format, rate;
++ struct gbaudio_data_connection *data;
++ struct gbaudio_stream_params *params;
++
++ /* find the dai */
++ data = find_data(module, id);
++ if (!data) {
++ dev_err(module->dev, "%d:DATA connection missing\n", id);
++ return -ENODEV;
++ }
++ module_state = data->state[SNDRV_PCM_STREAM_PLAYBACK];
++
++ params = find_dai_stream_params(codec, id, SNDRV_PCM_STREAM_PLAYBACK);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ return -EINVAL;
++ }
++
++ /* register cport */
++ if (module_state < GBAUDIO_CODEC_STARTUP) {
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_register_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_TX);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "reg_cport failed:%d\n", ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_PLAYBACK] =
++ GBAUDIO_CODEC_STARTUP;
++ dev_dbg(module->dev, "Dynamic Register %d DAI\n", cportid);
++ }
++
++ /* hw_params */
++ if (module_state < GBAUDIO_CODEC_HWPARAMS) {
++ format = params->format;
++ channels = params->channels;
++ rate = params->rate;
++ sig_bits = params->sig_bits;
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport,
++ format, rate, channels, sig_bits);
++ if (ret) {
++ dev_err_ratelimited(module->dev, "set_pcm failed:%d\n",
++ ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_PLAYBACK] =
++ GBAUDIO_CODEC_HWPARAMS;
++ dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport);
++ }
++
++ /* prepare */
++ if (module_state < GBAUDIO_CODEC_PREPARE) {
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_set_tx_data_size(module->mgmt_connection,
++ data_cport, 192);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "set_tx_data_size failed:%d\n",
++ ret);
++ return ret;
++ }
++ ret = gb_audio_gb_activate_tx(module->mgmt_connection,
++ data_cport);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "activate_tx failed:%d\n", ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_PLAYBACK] =
++ GBAUDIO_CODEC_PREPARE;
++ dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport);
++ }
++
++ return 0;
++}
++
++static int gbaudio_module_disable_tx(struct gbaudio_module_info *module, int id)
++{
++ int ret;
++ uint16_t data_cport, cportid, i2s_port;
++ int module_state;
++ struct gbaudio_data_connection *data;
++
++ /* find the dai */
++ data = find_data(module, id);
++ if (!data) {
++ dev_err(module->dev, "%d:DATA connection missing\n", id);
++ return -ENODEV;
++ }
++ module_state = data->state[SNDRV_PCM_STREAM_PLAYBACK];
++
++ if (module_state > GBAUDIO_CODEC_HWPARAMS) {
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
++ data_cport);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "deactivate_tx failed:%d\n", ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Dynamic deactivate %d DAI\n", data_cport);
++ data->state[SNDRV_PCM_STREAM_PLAYBACK] =
++ GBAUDIO_CODEC_HWPARAMS;
++ }
++
++ if (module_state > GBAUDIO_CODEC_SHUTDOWN) {
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_unregister_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_TX);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "unregister_cport failed:%d\n",
++ ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Dynamic Unregister %d DAI\n", cportid);
++ data->state[SNDRV_PCM_STREAM_PLAYBACK] =
++ GBAUDIO_CODEC_SHUTDOWN;
++ }
++
++ return 0;
++}
++
++static int gbaudio_module_enable_rx(struct gbaudio_codec_info *codec,
++ struct gbaudio_module_info *module, int id)
++{
++ int module_state, ret = 0;
++ uint16_t data_cport, i2s_port, cportid;
++ uint8_t sig_bits, channels;
++ uint32_t format, rate;
++ struct gbaudio_data_connection *data;
++ struct gbaudio_stream_params *params;
++
++ /* find the dai */
++ data = find_data(module, id);
++ if (!data) {
++ dev_err(module->dev, "%d:DATA connection missing\n", id);
++ return -ENODEV;
++ }
++ module_state = data->state[SNDRV_PCM_STREAM_CAPTURE];
++
++ params = find_dai_stream_params(codec, id, SNDRV_PCM_STREAM_CAPTURE);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ return -EINVAL;
++ }
++
++ /* register cport */
++ if (module_state < GBAUDIO_CODEC_STARTUP) {
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_register_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_RX);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "reg_cport failed:%d\n", ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_CAPTURE] =
++ GBAUDIO_CODEC_STARTUP;
++ dev_dbg(module->dev, "Dynamic Register %d DAI\n", cportid);
++ }
++
++ /* hw_params */
++ if (module_state < GBAUDIO_CODEC_HWPARAMS) {
++ format = params->format;
++ channels = params->channels;
++ rate = params->rate;
++ sig_bits = params->sig_bits;
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_set_pcm(module->mgmt_connection, data_cport,
++ format, rate, channels, sig_bits);
++ if (ret) {
++ dev_err_ratelimited(module->dev, "set_pcm failed:%d\n",
++ ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_CAPTURE] =
++ GBAUDIO_CODEC_HWPARAMS;
++ dev_dbg(module->dev, "Dynamic hw_params %d DAI\n", data_cport);
++ }
++
++ /* prepare */
++ if (module_state < GBAUDIO_CODEC_PREPARE) {
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_set_rx_data_size(module->mgmt_connection,
++ data_cport, 192);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "set_rx_data_size failed:%d\n",
++ ret);
++ return ret;
++ }
++ ret = gb_audio_gb_activate_rx(module->mgmt_connection,
++ data_cport);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "activate_rx failed:%d\n", ret);
++ return ret;
++ }
++ data->state[SNDRV_PCM_STREAM_CAPTURE] =
++ GBAUDIO_CODEC_PREPARE;
++ dev_dbg(module->dev, "Dynamic prepare %d DAI\n", data_cport);
++ }
++
++ return 0;
++}
++
++static int gbaudio_module_disable_rx(struct gbaudio_module_info *module, int id)
++{
++ int ret;
++ uint16_t data_cport, cportid, i2s_port;
++ int module_state;
++ struct gbaudio_data_connection *data;
++
++ /* find the dai */
++ data = find_data(module, id);
++ if (!data) {
++ dev_err(module->dev, "%d:DATA connection missing\n", id);
++ return -ENODEV;
++ }
++ module_state = data->state[SNDRV_PCM_STREAM_CAPTURE];
++
++ if (module_state > GBAUDIO_CODEC_HWPARAMS) {
++ data_cport = data->connection->intf_cport_id;
++ ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
++ data_cport);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "deactivate_rx failed:%d\n", ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Dynamic deactivate %d DAI\n", data_cport);
++ data->state[SNDRV_PCM_STREAM_CAPTURE] =
++ GBAUDIO_CODEC_HWPARAMS;
++ }
++
++ if (module_state > GBAUDIO_CODEC_SHUTDOWN) {
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_unregister_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_RX);
++ if (ret) {
++ dev_err_ratelimited(module->dev,
++ "unregister_cport failed:%d\n",
++ ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Dynamic Unregister %d DAI\n", cportid);
++ data->state[SNDRV_PCM_STREAM_CAPTURE] =
++ GBAUDIO_CODEC_SHUTDOWN;
++ }
++
++ return 0;
++}
++
++int gbaudio_module_update(struct gbaudio_codec_info *codec,
++ struct snd_soc_dapm_widget *w,
++ struct gbaudio_module_info *module, int enable)
++{
++ int dai_id, ret;
++ char intf_name[NAME_SIZE], dir[NAME_SIZE];
++
++ dev_dbg(module->dev, "%s:Module update %s sequence\n", w->name,
++ enable ? "Enable":"Disable");
++
++ if ((w->id != snd_soc_dapm_aif_in) && (w->id != snd_soc_dapm_aif_out)){
++ dev_dbg(codec->dev, "No action required for %s\n", w->name);
++ return 0;
++ }
++
++ /* parse dai_id from AIF widget's stream_name */
++ ret = sscanf(w->sname, "%s %d %s", intf_name, &dai_id, dir);
++ if (ret < 3) {
++ dev_err(codec->dev, "Error while parsing dai_id for %s\n",
++ w->name);
++ return -EINVAL;
++ }
++
++ mutex_lock(&codec->lock);
++ if (w->id == snd_soc_dapm_aif_in) {
++ if (enable)
++ ret = gbaudio_module_enable_tx(codec, module, dai_id);
++ else
++ ret = gbaudio_module_disable_tx(module, dai_id);
++ } else if (w->id == snd_soc_dapm_aif_out) {
++ if (enable)
++ ret = gbaudio_module_enable_rx(codec, module, dai_id);
++ else
++ ret = gbaudio_module_disable_rx(module, dai_id);
++ }
++
++ mutex_unlock(&codec->lock);
++
++ return ret;
++}
++EXPORT_SYMBOL(gbaudio_module_update);
++
++/*
++ * codec DAI ops
++ */
++static int gbcodec_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
++ struct gbaudio_stream_params *params;
++
++ mutex_lock(&codec->lock);
++
++ if (list_empty(&codec->module_list)) {
++ dev_err(codec->dev, "No codec module available\n");
++ mutex_unlock(&codec->lock);
++ return -ENODEV;
++ }
++
++ params = find_dai_stream_params(codec, dai->id, substream->stream);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++ params->state = GBAUDIO_CODEC_STARTUP;
++ mutex_unlock(&codec->lock);
++ /* to prevent suspend in case of active audio */
++ pm_stay_awake(dai->dev);
++
++ return 0;
++}
++
++static void gbcodec_shutdown(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
++ struct gbaudio_stream_params *params;
++
++ mutex_lock(&codec->lock);
++
++ if (list_empty(&codec->module_list))
++ dev_info(codec->dev, "No codec module available during shutdown\n");
++
++ params = find_dai_stream_params(codec, dai->id, substream->stream);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ mutex_unlock(&codec->lock);
++ return;
++ }
++ params->state = GBAUDIO_CODEC_SHUTDOWN;
++ mutex_unlock(&codec->lock);
++ pm_relax(dai->dev);
++ return;
++}
++
++static int gbcodec_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *hwparams,
++ struct snd_soc_dai *dai)
++{
++ int ret;
++ uint8_t sig_bits, channels;
++ uint32_t format, rate;
++ struct gbaudio_module_info *module;
++ struct gbaudio_data_connection *data;
++ struct gb_bundle *bundle;
++ struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
++ struct gbaudio_stream_params *params;
++
++ mutex_lock(&codec->lock);
++
++ if (list_empty(&codec->module_list)) {
++ dev_err(codec->dev, "No codec module available\n");
++ mutex_unlock(&codec->lock);
++ return -ENODEV;
++ }
++
++ /*
++ * assuming, currently only 48000 Hz, 16BIT_LE, stereo
++ * is supported, validate params before configuring codec
++ */
++ if (params_channels(hwparams) != 2) {
++ dev_err(dai->dev, "Invalid channel count:%d\n",
++ params_channels(hwparams));
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++ channels = params_channels(hwparams);
++
++ if (params_rate(hwparams) != 48000) {
++ dev_err(dai->dev, "Invalid sampling rate:%d\n",
++ params_rate(hwparams));
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++ rate = GB_AUDIO_PCM_RATE_48000;
++
++ if (params_format(hwparams) != SNDRV_PCM_FORMAT_S16_LE) {
++ dev_err(dai->dev, "Invalid format:%d\n",
++ params_format(hwparams));
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++ format = GB_AUDIO_PCM_FMT_S16_LE;
++
++ /* find the data connection */
++ list_for_each_entry(module, &codec->module_list, list) {
++ data = find_data(module, dai->id);
++ if (data)
++ break;
++ }
++
++ if (!data) {
++ dev_err(dai->dev, "DATA connection missing\n");
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++
++ params = find_dai_stream_params(codec, dai->id, substream->stream);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++
++ bundle = to_gb_bundle(module->dev);
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret) {
++ mutex_unlock(&codec->lock);
++ return ret;
++ }
++
++ ret = gb_audio_apbridgea_set_config(data->connection, 0,
++ AUDIO_APBRIDGEA_PCM_FMT_16,
++ AUDIO_APBRIDGEA_PCM_RATE_48000,
++ 6144000);
++ if (ret) {
++ dev_err_ratelimited(dai->dev, "%d: Error during set_config\n",
++ ret);
++ mutex_unlock(&codec->lock);
++ return ret;
++ }
++
++ gb_pm_runtime_put_noidle(bundle);
++
++ params->state = GBAUDIO_CODEC_HWPARAMS;
++ params->format = format;
++ params->rate = rate;
++ params->channels = channels;
++ params->sig_bits = sig_bits;
++
++ mutex_unlock(&codec->lock);
++ return 0;
++}
++
++static int gbcodec_prepare(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ int ret;
++ struct gbaudio_module_info *module;
++ struct gbaudio_data_connection *data;
++ struct gb_bundle *bundle;
++ struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
++ struct gbaudio_stream_params *params;
++
++ mutex_lock(&codec->lock);
++
++ if (list_empty(&codec->module_list)) {
++ dev_err(codec->dev, "No codec module available\n");
++ mutex_unlock(&codec->lock);
++ return -ENODEV;
++ }
++
++ list_for_each_entry(module, &codec->module_list, list) {
++ /* find the dai */
++ data = find_data(module, dai->id);
++ if (data)
++ break;
++ }
++ if (!data) {
++ dev_err(dai->dev, "DATA connection missing\n");
++ mutex_unlock(&codec->lock);
++ return -ENODEV;
++ }
++
++ params = find_dai_stream_params(codec, dai->id, substream->stream);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++
++ bundle = to_gb_bundle(module->dev);
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret) {
++ mutex_unlock(&codec->lock);
++ return ret;
++ }
++
++ switch (substream->stream) {
++ case SNDRV_PCM_STREAM_PLAYBACK:
++ ret = gb_audio_apbridgea_set_tx_data_size(data->connection, 0,
++ 192);
++ break;
++ case SNDRV_PCM_STREAM_CAPTURE:
++ ret = gb_audio_apbridgea_set_rx_data_size(data->connection, 0,
++ 192);
++ break;
++ }
++ if (ret) {
++ mutex_unlock(&codec->lock);
++ dev_err_ratelimited(dai->dev, "set_data_size failed:%d\n",
++ ret);
++ return ret;
++ }
++
++ gb_pm_runtime_put_noidle(bundle);
++
++ params->state = GBAUDIO_CODEC_PREPARE;
++ mutex_unlock(&codec->lock);
++ return 0;
++}
++
++static int gbcodec_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
++{
++ int ret;
++ struct gbaudio_data_connection *data;
++ struct gbaudio_module_info *module;
++ struct gb_bundle *bundle;
++ struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
++ struct gbaudio_stream_params *params;
++
++
++ dev_dbg(dai->dev, "Mute:%d, Direction:%s\n", mute,
++ stream ? "CAPTURE":"PLAYBACK");
++
++ mutex_lock(&codec->lock);
++
++ params = find_dai_stream_params(codec, dai->id, stream);
++ if (!params) {
++ dev_err(codec->dev, "Failed to fetch dai_stream pointer\n");
++ mutex_unlock(&codec->lock);
++ return -EINVAL;
++ }
++
++ if (list_empty(&codec->module_list)) {
++ dev_err(codec->dev, "No codec module available\n");
++ if (mute) {
++ params->state = GBAUDIO_CODEC_STOP;
++ ret = 0;
++ } else {
++ ret = -ENODEV;
++ }
++ mutex_unlock(&codec->lock);
++ return ret;
++ }
++
++ list_for_each_entry(module, &codec->module_list, list) {
++ /* find the dai */
++ data = find_data(module, dai->id);
++ if (data)
++ break;
++ }
++ if (!data) {
++ dev_err(dai->dev, "%s:%s DATA connection missing\n",
++ dai->name, module->name);
++ mutex_unlock(&codec->lock);
++ return -ENODEV;
++ }
++
++ bundle = to_gb_bundle(module->dev);
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret) {
++ mutex_unlock(&codec->lock);
++ return ret;
++ }
++
++ if (!mute && !stream) {/* start playback */
++ ret = gb_audio_apbridgea_prepare_tx(data->connection,
++ 0);
++ if (!ret)
++ ret = gb_audio_apbridgea_start_tx(data->connection,
++ 0, 0);
++ params->state = GBAUDIO_CODEC_START;
++ } else if (!mute && stream) {/* start capture */
++ ret = gb_audio_apbridgea_prepare_rx(data->connection,
++ 0);
++ if (!ret)
++ ret = gb_audio_apbridgea_start_rx(data->connection,
++ 0);
++ params->state = GBAUDIO_CODEC_START;
++ } else if (mute && !stream) {/* stop playback */
++ ret = gb_audio_apbridgea_stop_tx(data->connection, 0);
++ if (!ret)
++ ret = gb_audio_apbridgea_shutdown_tx(data->connection,
++ 0);
++ params->state = GBAUDIO_CODEC_STOP;
++ } else if (mute && stream) {/* stop capture */
++ ret = gb_audio_apbridgea_stop_rx(data->connection, 0);
++ if (!ret)
++ ret = gb_audio_apbridgea_shutdown_rx(data->connection,
++ 0);
++ params->state = GBAUDIO_CODEC_STOP;
++ } else
++ ret = -EINVAL;
++ if (ret)
++ dev_err_ratelimited(dai->dev,
++ "%s:Error during %s %s stream:%d\n",
++ module->name, mute ? "Mute" : "Unmute",
++ stream ? "Capture" : "Playback", ret);
++
++ gb_pm_runtime_put_noidle(bundle);
++ mutex_unlock(&codec->lock);
++ return ret;
++}
++
++static struct snd_soc_dai_ops gbcodec_dai_ops = {
++ .startup = gbcodec_startup,
++ .shutdown = gbcodec_shutdown,
++ .hw_params = gbcodec_hw_params,
++ .prepare = gbcodec_prepare,
++ .mute_stream = gbcodec_mute_stream,
++};
++
++static struct snd_soc_dai_driver gbaudio_dai[] = {
++ {
++ .name = "apb-i2s0",
++ .id = 0,
++ .playback = {
++ .stream_name = "I2S 0 Playback",
++ .rates = SNDRV_PCM_RATE_48000,
++ .formats = SNDRV_PCM_FORMAT_S16_LE,
++ .rate_max = 48000,
++ .rate_min = 48000,
++ .channels_min = 1,
++ .channels_max = 2,
++ },
++ .capture = {
++ .stream_name = "I2S 0 Capture",
++ .rates = SNDRV_PCM_RATE_48000,
++ .formats = SNDRV_PCM_FORMAT_S16_LE,
++ .rate_max = 48000,
++ .rate_min = 48000,
++ .channels_min = 1,
++ .channels_max = 2,
++ },
++ .ops = &gbcodec_dai_ops,
++ },
++};
++
++static int gbaudio_init_jack(struct gbaudio_module_info *module,
++ struct snd_soc_codec *codec)
++{
++ int ret;
++
++ if (!module->jack_mask)
++ return 0;
++
++ snprintf(module->jack_name, NAME_SIZE, "GB %d Headset Jack",
++ module->dev_id);
++ ret = snd_soc_jack_new(codec, module->jack_name, module->jack_mask,
++ &module->headset_jack);
++ if (ret) {
++ dev_err(module->dev, "Failed to create new jack\n");
++ return ret;
++ }
++
++ if (!module->button_mask)
++ return 0;
++
++ snprintf(module->button_name, NAME_SIZE, "GB %d Button Jack",
++ module->dev_id);
++ ret = snd_soc_jack_new(codec, module->button_name, module->button_mask,
++ &module->button_jack);
++ if (ret) {
++ dev_err(module->dev, "Failed to create button jack\n");
++ return ret;
++ }
++
++ /*
++ * Currently, max 4 buttons are supported with following key mapping
++ * BTN_0 = KEY_MEDIA
++ * BTN_1 = KEY_VOICECOMMAND
++ * BTN_2 = KEY_VOLUMEUP
++ * BTN_3 = KEY_VOLUMEDOWN
++ */
++
++ if (module->button_mask & SND_JACK_BTN_0) {
++ ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_0,
++ KEY_MEDIA);
++ if (ret) {
++ dev_err(module->dev, "Failed to set BTN_0\n");
++ return ret;
++ }
++ }
++
++ if (module->button_mask & SND_JACK_BTN_1) {
++ ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_1,
++ KEY_VOICECOMMAND);
++ if (ret) {
++ dev_err(module->dev, "Failed to set BTN_1\n");
++ return ret;
++ }
++ }
++
++ if (module->button_mask & SND_JACK_BTN_2) {
++ ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_2,
++ KEY_VOLUMEUP);
++ if (ret) {
++ dev_err(module->dev, "Failed to set BTN_2\n");
++ return ret;
++ }
++ }
++
++ if (module->button_mask & SND_JACK_BTN_3) {
++ ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_3,
++ KEY_VOLUMEDOWN);
++ if (ret) {
++ dev_err(module->dev, "Failed to set BTN_0\n");
++ return ret;
++ }
++ }
++
++ /* FIXME
++ * verify if this is really required
++ set_bit(INPUT_PROP_NO_DUMMY_RELEASE,
++ module->button_jack.jack->input_dev->propbit);
++ */
++
++ return 0;
++}
++
++int gbaudio_register_module(struct gbaudio_module_info *module)
++{
++ int ret;
++ struct snd_soc_codec *codec;
++ struct snd_card *card;
++ struct snd_soc_jack *jack = NULL;
++
++ if (!gbcodec) {
++ dev_err(module->dev, "GB Codec not yet probed\n");
++ return -EAGAIN;
++ }
++
++ codec = gbcodec->codec;
++ card = codec->card->snd_card;
++
++ down_write(&card->controls_rwsem);
++
++ if (module->num_dais) {
++ dev_err(gbcodec->dev,
++ "%d:DAIs not supported via gbcodec driver\n",
++ module->num_dais);
++ up_write(&card->controls_rwsem);
++ return -EINVAL;
++ }
++
++ ret = gbaudio_init_jack(module, codec);
++ if (ret) {
++ up_write(&card->controls_rwsem);
++ return ret;
++ }
++
++ if (module->dapm_widgets)
++ snd_soc_dapm_new_controls(&codec->dapm, module->dapm_widgets,
++ module->num_dapm_widgets);
++ if (module->controls)
++ snd_soc_add_codec_controls(codec, module->controls,
++ module->num_controls);
++ if (module->dapm_routes)
++ snd_soc_dapm_add_routes(&codec->dapm, module->dapm_routes,
++ module->num_dapm_routes);
++
++ /* card already instantiated, create widgets here only */
++ if (codec->card->instantiated) {
++ snd_soc_dapm_link_component_dai_widgets(codec->card,
++ &codec->dapm);
++#ifdef CONFIG_SND_JACK
++ /* register jack devices for this module from codec->jack_list */
++ list_for_each_entry(jack, &codec->jack_list, list) {
++ if ((jack == &module->headset_jack)
++ || (jack == &module->button_jack))
++ snd_device_register(codec->card->snd_card,
++ jack->jack);
++ }
++#endif
++ }
++
++ mutex_lock(&gbcodec->lock);
++ list_add(&module->list, &gbcodec->module_list);
++ mutex_unlock(&gbcodec->lock);
++
++ if (codec->card->instantiated)
++ ret = snd_soc_dapm_new_widgets(&codec->dapm);
++ dev_dbg(codec->dev, "Registered %s module\n", module->name);
++
++ up_write(&card->controls_rwsem);
++ return ret;
++}
++EXPORT_SYMBOL(gbaudio_register_module);
++
++static void gbaudio_codec_clean_data_tx(struct gbaudio_data_connection *data)
++{
++ uint16_t i2s_port, cportid;
++ int ret;
++
++ if (list_is_singular(&gbcodec->module_list)) {
++ ret = gb_audio_apbridgea_stop_tx(data->connection, 0);
++ if (ret)
++ return;
++ ret = gb_audio_apbridgea_shutdown_tx(data->connection,
++ 0);
++ if (ret)
++ return;
++ }
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_unregister_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_TX);
++ data->state[0] = GBAUDIO_CODEC_SHUTDOWN;
++}
++
++static void gbaudio_codec_clean_data_rx(struct gbaudio_data_connection *data)
++{
++ uint16_t i2s_port, cportid;
++ int ret;
++
++ if (list_is_singular(&gbcodec->module_list)) {
++ ret = gb_audio_apbridgea_stop_rx(data->connection, 0);
++ if (ret)
++ return;
++ ret = gb_audio_apbridgea_shutdown_rx(data->connection,
++ 0);
++ if (ret)
++ return;
++ }
++ i2s_port = 0; /* fixed for now */
++ cportid = data->connection->hd_cport_id;
++ ret = gb_audio_apbridgea_unregister_cport(data->connection,
++ i2s_port, cportid,
++ AUDIO_APBRIDGEA_DIRECTION_RX);
++ data->state[1] = GBAUDIO_CODEC_SHUTDOWN;
++}
++
++
++static void gbaudio_codec_cleanup(struct gbaudio_module_info *module)
++{
++ struct gbaudio_data_connection *data;
++ int pb_state, cap_state;
++
++ dev_dbg(gbcodec->dev, "%s: removed, cleanup APBridge\n", module->name);
++ list_for_each_entry(data, &module->data_list, list) {
++ pb_state = data->state[0];
++ cap_state = data->state[1];
++
++ if (pb_state > GBAUDIO_CODEC_SHUTDOWN)
++ gbaudio_codec_clean_data_tx(data);
++
++ if (cap_state > GBAUDIO_CODEC_SHUTDOWN)
++ gbaudio_codec_clean_data_rx(data);
++
++ }
++}
++
++void gbaudio_unregister_module(struct gbaudio_module_info *module)
++{
++ struct snd_soc_codec *codec = gbcodec->codec;
++ struct snd_card *card = codec->card->snd_card;
++ struct snd_soc_jack *jack, *next_j;
++ int mask;
++
++ dev_dbg(codec->dev, "Unregister %s module\n", module->name);
++
++ down_write(&card->controls_rwsem);
++ mutex_lock(&gbcodec->lock);
++ gbaudio_codec_cleanup(module);
++ list_del(&module->list);
++ dev_dbg(codec->dev, "Process Unregister %s module\n", module->name);
++ mutex_unlock(&gbcodec->lock);
++
++#ifdef CONFIG_SND_JACK
++ /* free jack devices for this module from codec->jack_list */
++ list_for_each_entry_safe(jack, next_j, &codec->jack_list, list) {
++ if (jack == &module->headset_jack)
++ mask = GBCODEC_JACK_MASK;
++ else if (jack == &module->button_jack)
++ mask = GBCODEC_JACK_BUTTON_MASK;
++ else
++ mask = 0;
++ if (mask) {
++ dev_dbg(module->dev, "Report %s removal\n",
++ jack->jack->id);
++ snd_soc_jack_report(jack, 0, mask);
++ snd_device_free(codec->card->snd_card, jack->jack);
++ list_del(&jack->list);
++ }
++ }
++#endif
++
++ if (module->dapm_routes) {
++ dev_dbg(codec->dev, "Removing %d routes\n",
++ module->num_dapm_routes);
++ snd_soc_dapm_del_routes(&codec->dapm, module->dapm_routes,
++ module->num_dapm_routes);
++ }
++ if (module->controls) {
++ dev_dbg(codec->dev, "Removing %d controls\n",
++ module->num_controls);
++ snd_soc_remove_codec_controls(codec, module->controls,
++ module->num_controls);
++ }
++ if (module->dapm_widgets) {
++ dev_dbg(codec->dev, "Removing %d widgets\n",
++ module->num_dapm_widgets);
++ snd_soc_dapm_free_controls(&codec->dapm, module->dapm_widgets,
++ module->num_dapm_widgets);
++ }
++
++ dev_dbg(codec->dev, "Unregistered %s module\n", module->name);
++
++ up_write(&card->controls_rwsem);
++}
++EXPORT_SYMBOL(gbaudio_unregister_module);
++
++/*
++ * codec driver ops
++ */
++static int gbcodec_probe(struct snd_soc_codec *codec)
++{
++ int i;
++ struct gbaudio_codec_info *info;
++ struct gbaudio_codec_dai *dai;
++
++ info = devm_kzalloc(codec->dev, sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ info->dev = codec->dev;
++ INIT_LIST_HEAD(&info->module_list);
++ mutex_init(&info->lock);
++ INIT_LIST_HEAD(&info->dai_list);
++
++ /* init dai_list used to maintain runtime stream info */
++ for (i = 0; i < ARRAY_SIZE(gbaudio_dai); i++) {
++ dai = devm_kzalloc(codec->dev, sizeof(*dai), GFP_KERNEL);
++ if (!dai)
++ return -ENOMEM;
++ dai->id = gbaudio_dai[i].id;
++ list_add(&dai->list, &info->dai_list);
++ }
++
++ info->codec = codec;
++ snd_soc_codec_set_drvdata(codec, info);
++ gbcodec = info;
++
++ device_init_wakeup(codec->dev, 1);
++ return 0;
++}
++
++static int gbcodec_remove(struct snd_soc_codec *codec)
++{
++ /* Empty function for now */
++ return 0;
++}
++
++static u8 gbcodec_reg[GBCODEC_REG_COUNT] = {
++ [GBCODEC_CTL_REG] = GBCODEC_CTL_REG_DEFAULT,
++ [GBCODEC_MUTE_REG] = GBCODEC_MUTE_REG_DEFAULT,
++ [GBCODEC_PB_LVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
++ [GBCODEC_PB_RVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
++ [GBCODEC_CAP_LVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
++ [GBCODEC_CAP_RVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
++ [GBCODEC_APB1_MUX_REG] = GBCODEC_APB1_MUX_REG_DEFAULT,
++ [GBCODEC_APB2_MUX_REG] = GBCODEC_APB2_MUX_REG_DEFAULT,
++};
++
++static int gbcodec_write(struct snd_soc_codec *codec, unsigned int reg,
++ unsigned int value)
++{
++ int ret = 0;
++
++ if (reg == SND_SOC_NOPM)
++ return 0;
++
++ BUG_ON(reg >= GBCODEC_REG_COUNT);
++
++ gbcodec_reg[reg] = value;
++ dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, value);
++
++ return ret;
++}
++
++static unsigned int gbcodec_read(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ unsigned int val = 0;
++
++ if (reg == SND_SOC_NOPM)
++ return 0;
++
++ BUG_ON(reg >= GBCODEC_REG_COUNT);
++
++ val = gbcodec_reg[reg];
++ dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, val);
++
++ return val;
++}
++
++static struct snd_soc_codec_driver soc_codec_dev_gbaudio = {
++ .probe = gbcodec_probe,
++ .remove = gbcodec_remove,
++
++ .read = gbcodec_read,
++ .write = gbcodec_write,
++
++ .reg_cache_size = GBCODEC_REG_COUNT,
++ .reg_cache_default = gbcodec_reg_defaults,
++ .reg_word_size = 1,
++
++ .idle_bias_off = true,
++ .ignore_pmdown_time = 1,
++};
++
++#ifdef CONFIG_PM
++static int gbaudio_codec_suspend(struct device *dev)
++{
++ dev_dbg(dev, "%s: suspend\n", __func__);
++ return 0;
++}
++
++static int gbaudio_codec_resume(struct device *dev)
++{
++ dev_dbg(dev, "%s: resume\n", __func__);
++ return 0;
++}
++
++static const struct dev_pm_ops gbaudio_codec_pm_ops = {
++ .suspend = gbaudio_codec_suspend,
++ .resume = gbaudio_codec_resume,
++};
++#endif
++
++static int gbaudio_codec_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_gbaudio,
++ gbaudio_dai, ARRAY_SIZE(gbaudio_dai));
++}
++
++static int gbaudio_codec_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_codec(&pdev->dev);
++ return 0;
++}
++
++static const struct of_device_id greybus_asoc_machine_of_match[] = {
++ { .compatible = "toshiba,apb-dummy-codec", },
++ {},
++};
++
++static struct platform_driver gbaudio_codec_driver = {
++ .driver = {
++ .name = "apb-dummy-codec",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++ .pm = &gbaudio_codec_pm_ops,
++#endif
++ .of_match_table = greybus_asoc_machine_of_match,
++ },
++ .probe = gbaudio_codec_probe,
++ .remove = gbaudio_codec_remove,
++};
++module_platform_driver(gbaudio_codec_driver);
++
++MODULE_DESCRIPTION("APBridge ALSA SoC dummy codec driver");
++MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:apb-dummy-codec");
+--- /dev/null
++++ b/drivers/greybus/audio_codec.h
+@@ -0,0 +1,283 @@
++/*
++ * Greybus audio driver
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __LINUX_GBAUDIO_CODEC_H
++#define __LINUX_GBAUDIO_CODEC_H
++
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "greybus.h"
++#include "greybus_protocols.h"
++
++#define NAME_SIZE 32
++#define MAX_DAIS 2 /* APB1, APB2 */
++
++enum {
++ APB1_PCM = 0,
++ APB2_PCM,
++ NUM_CODEC_DAIS,
++};
++
++enum gbcodec_reg_index {
++ GBCODEC_CTL_REG,
++ GBCODEC_MUTE_REG,
++ GBCODEC_PB_LVOL_REG,
++ GBCODEC_PB_RVOL_REG,
++ GBCODEC_CAP_LVOL_REG,
++ GBCODEC_CAP_RVOL_REG,
++ GBCODEC_APB1_MUX_REG,
++ GBCODEC_APB2_MUX_REG,
++ GBCODEC_REG_COUNT
++};
++
++/* device_type should be same as defined in audio.h (Android media layer) */
++enum {
++ GBAUDIO_DEVICE_NONE = 0x0,
++ /* reserved bits */
++ GBAUDIO_DEVICE_BIT_IN = 0x80000000,
++ GBAUDIO_DEVICE_BIT_DEFAULT = 0x40000000,
++ /* output devices */
++ GBAUDIO_DEVICE_OUT_SPEAKER = 0x2,
++ GBAUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4,
++ GBAUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8,
++ /* input devices */
++ GBAUDIO_DEVICE_IN_BUILTIN_MIC = GBAUDIO_DEVICE_BIT_IN | 0x4,
++ GBAUDIO_DEVICE_IN_WIRED_HEADSET = GBAUDIO_DEVICE_BIT_IN | 0x10,
++};
++
++/* bit 0-SPK, 1-HP, 2-DAC,
++ * 4-MIC, 5-HSMIC, 6-MIC2
++ */
++#define GBCODEC_CTL_REG_DEFAULT 0x00
++
++/* bit 0,1 - APB1-PB-L/R
++ * bit 2,3 - APB2-PB-L/R
++ * bit 4,5 - APB1-Cap-L/R
++ * bit 6,7 - APB2-Cap-L/R
++ */
++#define GBCODEC_MUTE_REG_DEFAULT 0x00
++
++/* 0-127 steps */
++#define GBCODEC_PB_VOL_REG_DEFAULT 0x00
++#define GBCODEC_CAP_VOL_REG_DEFAULT 0x00
++
++/* bit 0,1,2 - PB stereo, left, right
++ * bit 8,9,10 - Cap stereo, left, right
++ */
++#define GBCODEC_APB1_MUX_REG_DEFAULT 0x00
++#define GBCODEC_APB2_MUX_REG_DEFAULT 0x00
++
++#define GBCODEC_JACK_MASK 0x0000FFFF
++#define GBCODEC_JACK_BUTTON_MASK 0xFFFF0000
++
++static const u8 gbcodec_reg_defaults[GBCODEC_REG_COUNT] = {
++ GBCODEC_CTL_REG_DEFAULT,
++ GBCODEC_MUTE_REG_DEFAULT,
++ GBCODEC_PB_VOL_REG_DEFAULT,
++ GBCODEC_PB_VOL_REG_DEFAULT,
++ GBCODEC_CAP_VOL_REG_DEFAULT,
++ GBCODEC_CAP_VOL_REG_DEFAULT,
++ GBCODEC_APB1_MUX_REG_DEFAULT,
++ GBCODEC_APB2_MUX_REG_DEFAULT,
++};
++
++enum gbaudio_codec_state {
++ GBAUDIO_CODEC_SHUTDOWN = 0,
++ GBAUDIO_CODEC_STARTUP,
++ GBAUDIO_CODEC_HWPARAMS,
++ GBAUDIO_CODEC_PREPARE,
++ GBAUDIO_CODEC_START,
++ GBAUDIO_CODEC_STOP,
++};
++
++struct gbaudio_stream_params {
++ int state;
++ uint8_t sig_bits, channels;
++ uint32_t format, rate;
++};
++
++struct gbaudio_codec_dai {
++ int id;
++ /* runtime params for playback/capture streams */
++ struct gbaudio_stream_params params[2];
++ struct list_head list;
++};
++
++struct gbaudio_codec_info {
++ struct device *dev;
++ struct snd_soc_codec *codec;
++ struct list_head module_list;
++ /* to maintain runtime stream params for each DAI */
++ struct list_head dai_list;
++ struct mutex lock;
++ u8 reg[GBCODEC_REG_COUNT];
++};
++
++struct gbaudio_widget {
++ __u8 id;
++ const char *name;
++ struct list_head list;
++};
++
++struct gbaudio_control {
++ __u8 id;
++ char *name;
++ char *wname;
++ const char * const *texts;
++ int items;
++ struct list_head list;
++};
++
++struct gbaudio_data_connection {
++ int id;
++ __le16 data_cport;
++ struct gb_connection *connection;
++ struct list_head list;
++ /* maintain runtime state for playback/capture stream */
++ int state[2];
++};
++
++/* stream direction */
++#define GB_PLAYBACK BIT(0)
++#define GB_CAPTURE BIT(1)
++
++enum gbaudio_module_state {
++ GBAUDIO_MODULE_OFF = 0,
++ GBAUDIO_MODULE_ON,
++};
++
++struct gbaudio_module_info {
++ /* module info */
++ struct device *dev;
++ int dev_id; /* check if it should be bundle_id/hd_cport_id */
++ int vid;
++ int pid;
++ int slot;
++ int type;
++ int set_uevent;
++ char vstr[NAME_SIZE];
++ char pstr[NAME_SIZE];
++ struct list_head list;
++ /* need to share this info to above user space */
++ int manager_id;
++ char name[NAME_SIZE];
++ unsigned int ip_devices;
++ unsigned int op_devices;
++
++ /* jack related */
++ char jack_name[NAME_SIZE];
++ char button_name[NAME_SIZE];
++ int jack_type;
++ int jack_mask;
++ int button_mask;
++ int button_status;
++ struct snd_soc_jack headset_jack;
++ struct snd_soc_jack button_jack;
++
++ /* connection info */
++ struct gb_connection *mgmt_connection;
++ size_t num_data_connections;
++ struct list_head data_list;
++
++ /* topology related */
++ int num_dais;
++ int num_controls;
++ int num_dapm_widgets;
++ int num_dapm_routes;
++ unsigned long dai_offset;
++ unsigned long widget_offset;
++ unsigned long control_offset;
++ unsigned long route_offset;
++ struct snd_kcontrol_new *controls;
++ struct snd_soc_dapm_widget *dapm_widgets;
++ struct snd_soc_dapm_route *dapm_routes;
++ struct snd_soc_dai_driver *dais;
++
++ struct list_head widget_list;
++ struct list_head ctl_list;
++ struct list_head widget_ctl_list;
++
++ struct gb_audio_topology *topology;
++};
++
++int gbaudio_tplg_parse_data(struct gbaudio_module_info *module,
++ struct gb_audio_topology *tplg_data);
++void gbaudio_tplg_release(struct gbaudio_module_info *module);
++
++int gbaudio_module_update(struct gbaudio_codec_info *codec,
++ struct snd_soc_dapm_widget *w,
++ struct gbaudio_module_info *module,
++ int enable);
++int gbaudio_register_module(struct gbaudio_module_info *module);
++void gbaudio_unregister_module(struct gbaudio_module_info *module);
++
++/* protocol related */
++extern int gb_audio_gb_get_topology(struct gb_connection *connection,
++ struct gb_audio_topology **topology);
++extern int gb_audio_gb_get_control(struct gb_connection *connection,
++ uint8_t control_id, uint8_t index,
++ struct gb_audio_ctl_elem_value *value);
++extern int gb_audio_gb_set_control(struct gb_connection *connection,
++ uint8_t control_id, uint8_t index,
++ struct gb_audio_ctl_elem_value *value);
++extern int gb_audio_gb_enable_widget(struct gb_connection *connection,
++ uint8_t widget_id);
++extern int gb_audio_gb_disable_widget(struct gb_connection *connection,
++ uint8_t widget_id);
++extern int gb_audio_gb_get_pcm(struct gb_connection *connection,
++ uint16_t data_cport, uint32_t *format,
++ uint32_t *rate, uint8_t *channels,
++ uint8_t *sig_bits);
++extern int gb_audio_gb_set_pcm(struct gb_connection *connection,
++ uint16_t data_cport, uint32_t format,
++ uint32_t rate, uint8_t channels,
++ uint8_t sig_bits);
++extern int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
++ uint16_t data_cport, uint16_t size);
++extern int gb_audio_gb_activate_tx(struct gb_connection *connection,
++ uint16_t data_cport);
++extern int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
++ uint16_t data_cport);
++extern int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
++ uint16_t data_cport, uint16_t size);
++extern int gb_audio_gb_activate_rx(struct gb_connection *connection,
++ uint16_t data_cport);
++extern int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
++ uint16_t data_cport);
++extern int gb_audio_apbridgea_set_config(struct gb_connection *connection,
++ __u16 i2s_port, __u32 format,
++ __u32 rate, __u32 mclk_freq);
++extern int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
++ __u16 i2s_port, __u16 cportid,
++ __u8 direction);
++extern int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
++ __u16 i2s_port, __u16 cportid,
++ __u8 direction);
++extern int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection,
++ __u16 i2s_port, __u16 size);
++extern int gb_audio_apbridgea_prepare_tx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
++ __u16 i2s_port, __u64 timestamp);
++extern int gb_audio_apbridgea_stop_tx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_shutdown_tx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
++ __u16 i2s_port, __u16 size);
++extern int gb_audio_apbridgea_prepare_rx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_stop_rx(struct gb_connection *connection,
++ __u16 i2s_port);
++extern int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection,
++ __u16 i2s_port);
++
++#endif /* __LINUX_GBAUDIO_CODEC_H */
+--- /dev/null
++++ b/drivers/greybus/audio_gb.c
+@@ -0,0 +1,228 @@
++/*
++ * Greybus Audio Device Class Protocol helpers
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++#include "greybus_protocols.h"
++#include "operation.h"
++#include "audio_codec.h"
++
++/* TODO: Split into separate calls */
++int gb_audio_gb_get_topology(struct gb_connection *connection,
++ struct gb_audio_topology **topology)
++{
++ struct gb_audio_get_topology_size_response size_resp;
++ struct gb_audio_topology *topo;
++ uint16_t size;
++ int ret;
++
++ ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE,
++ NULL, 0, &size_resp, sizeof(size_resp));
++ if (ret)
++ return ret;
++
++ size = le16_to_cpu(size_resp.size);
++ if (size < sizeof(*topo))
++ return -ENODATA;
++
++ topo = kzalloc(size, GFP_KERNEL);
++ if (!topo)
++ return -ENOMEM;
++
++ ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY, NULL, 0,
++ topo, size);
++ if (ret) {
++ kfree(topo);
++ return ret;
++ }
++
++ *topology = topo;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology);
++
++int gb_audio_gb_get_control(struct gb_connection *connection,
++ uint8_t control_id, uint8_t index,
++ struct gb_audio_ctl_elem_value *value)
++{
++ struct gb_audio_get_control_request req;
++ struct gb_audio_get_control_response resp;
++ int ret;
++
++ req.control_id = control_id;
++ req.index = index;
++
++ ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_CONTROL,
++ &req, sizeof(req), &resp, sizeof(resp));
++ if (ret)
++ return ret;
++
++ memcpy(value, &resp.value, sizeof(*value));
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_get_control);
++
++int gb_audio_gb_set_control(struct gb_connection *connection,
++ uint8_t control_id, uint8_t index,
++ struct gb_audio_ctl_elem_value *value)
++{
++ struct gb_audio_set_control_request req;
++
++ req.control_id = control_id;
++ req.index = index;
++ memcpy(&req.value, value, sizeof(req.value));
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_CONTROL,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_set_control);
++
++int gb_audio_gb_enable_widget(struct gb_connection *connection,
++ uint8_t widget_id)
++{
++ struct gb_audio_enable_widget_request req;
++
++ req.widget_id = widget_id;
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_ENABLE_WIDGET,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget);
++
++int gb_audio_gb_disable_widget(struct gb_connection *connection,
++ uint8_t widget_id)
++{
++ struct gb_audio_disable_widget_request req;
++
++ req.widget_id = widget_id;
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_DISABLE_WIDGET,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
++
++int gb_audio_gb_get_pcm(struct gb_connection *connection, uint16_t data_cport,
++ uint32_t *format, uint32_t *rate, uint8_t *channels,
++ uint8_t *sig_bits)
++{
++ struct gb_audio_get_pcm_request req;
++ struct gb_audio_get_pcm_response resp;
++ int ret;
++
++ req.data_cport = cpu_to_le16(data_cport);
++
++ ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_PCM,
++ &req, sizeof(req), &resp, sizeof(resp));
++ if (ret)
++ return ret;
++
++ *format = le32_to_cpu(resp.format);
++ *rate = le32_to_cpu(resp.rate);
++ *channels = resp.channels;
++ *sig_bits = resp.sig_bits;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
++
++int gb_audio_gb_set_pcm(struct gb_connection *connection, uint16_t data_cport,
++ uint32_t format, uint32_t rate, uint8_t channels,
++ uint8_t sig_bits)
++{
++ struct gb_audio_set_pcm_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++ req.format = cpu_to_le32(format);
++ req.rate = cpu_to_le32(rate);
++ req.channels = channels;
++ req.sig_bits = sig_bits;
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_PCM,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm);
++
++int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
++ uint16_t data_cport, uint16_t size)
++{
++ struct gb_audio_set_tx_data_size_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++ req.size = cpu_to_le16(size);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_TX_DATA_SIZE,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size);
++
++int gb_audio_gb_activate_tx(struct gb_connection *connection,
++ uint16_t data_cport)
++{
++ struct gb_audio_activate_tx_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_TX,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx);
++
++int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
++ uint16_t data_cport)
++{
++ struct gb_audio_deactivate_tx_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_TX,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx);
++
++int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
++ uint16_t data_cport, uint16_t size)
++{
++ struct gb_audio_set_rx_data_size_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++ req.size = cpu_to_le16(size);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_RX_DATA_SIZE,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size);
++
++int gb_audio_gb_activate_rx(struct gb_connection *connection,
++ uint16_t data_cport)
++{
++ struct gb_audio_activate_rx_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_RX,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx);
++
++int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
++ uint16_t data_cport)
++{
++ struct gb_audio_deactivate_rx_request req;
++
++ req.data_cport = cpu_to_le16(data_cport);
++
++ return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_RX,
++ &req, sizeof(req), NULL, 0);
++}
++EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_rx);
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("greybus:audio-gb");
++MODULE_DESCRIPTION("Greybus Audio Device Class Protocol library");
++MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
+--- /dev/null
++++ b/drivers/greybus/audio_manager.c
+@@ -0,0 +1,184 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/string.h>
++#include <linux/sysfs.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/rwlock.h>
++#include <linux/idr.h>
++
++#include "audio_manager.h"
++#include "audio_manager_private.h"
++
++static struct kset *manager_kset;
++
++static LIST_HEAD(modules_list);
++static DECLARE_RWSEM(modules_rwsem);
++static DEFINE_IDA(module_id);
++
++/* helpers */
++static struct gb_audio_manager_module *gb_audio_manager_get_locked(int id)
++{
++ struct gb_audio_manager_module *module;
++
++ if (id < 0)
++ return NULL;
++
++ list_for_each_entry(module, &modules_list, list) {
++ if (module->id == id)
++ return module;
++ }
++
++ return NULL;
++}
++
++/* public API */
++int gb_audio_manager_add(struct gb_audio_manager_module_descriptor *desc)
++{
++ struct gb_audio_manager_module *module;
++ int id;
++ int err;
++
++ id = ida_simple_get(&module_id, 0, 0, GFP_KERNEL);
++ err = gb_audio_manager_module_create(&module, manager_kset,
++ id, desc);
++ if (err) {
++ ida_simple_remove(&module_id, id);
++ return err;
++ }
++
++ /* Add it to the list */
++ down_write(&modules_rwsem);
++ list_add_tail(&module->list, &modules_list);
++ up_write(&modules_rwsem);
++
++ return module->id;
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_add);
++
++int gb_audio_manager_remove(int id)
++{
++ struct gb_audio_manager_module *module;
++
++ down_write(&modules_rwsem);
++
++ module = gb_audio_manager_get_locked(id);
++ if (!module) {
++ up_write(&modules_rwsem);
++ return -EINVAL;
++ }
++ list_del(&module->list);
++ kobject_put(&module->kobj);
++ up_write(&modules_rwsem);
++ ida_simple_remove(&module_id, id);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_remove);
++
++void gb_audio_manager_remove_all(void)
++{
++ struct gb_audio_manager_module *module, *next;
++ int is_empty = 1;
++
++ down_write(&modules_rwsem);
++
++ list_for_each_entry_safe(module, next, &modules_list, list) {
++ list_del(&module->list);
++ kobject_put(&module->kobj);
++ ida_simple_remove(&module_id, module->id);
++ }
++
++ is_empty = list_empty(&modules_list);
++
++ up_write(&modules_rwsem);
++
++ if (!is_empty)
++ pr_warn("Not all nodes were deleted\n");
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_remove_all);
++
++struct gb_audio_manager_module *gb_audio_manager_get_module(int id)
++{
++ struct gb_audio_manager_module *module;
++
++ down_read(&modules_rwsem);
++ module = gb_audio_manager_get_locked(id);
++ kobject_get(&module->kobj);
++ up_read(&modules_rwsem);
++ return module;
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_get_module);
++
++void gb_audio_manager_put_module(struct gb_audio_manager_module *module)
++{
++ kobject_put(&module->kobj);
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_put_module);
++
++int gb_audio_manager_dump_module(int id)
++{
++ struct gb_audio_manager_module *module;
++
++ down_read(&modules_rwsem);
++ module = gb_audio_manager_get_locked(id);
++ up_read(&modules_rwsem);
++
++ if (!module)
++ return -EINVAL;
++
++ gb_audio_manager_module_dump(module);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_dump_module);
++
++void gb_audio_manager_dump_all(void)
++{
++ struct gb_audio_manager_module *module;
++ int count = 0;
++
++ down_read(&modules_rwsem);
++ list_for_each_entry(module, &modules_list, list) {
++ gb_audio_manager_module_dump(module);
++ count++;
++ }
++ up_read(&modules_rwsem);
++
++ pr_info("Number of connected modules: %d\n", count);
++}
++EXPORT_SYMBOL_GPL(gb_audio_manager_dump_all);
++
++/*
++ * module init/deinit
++ */
++static int __init manager_init(void)
++{
++ manager_kset = kset_create_and_add(GB_AUDIO_MANAGER_NAME, NULL,
++ kernel_kobj);
++ if (!manager_kset)
++ return -ENOMEM;
++
++#ifdef GB_AUDIO_MANAGER_SYSFS
++ gb_audio_manager_sysfs_init(&manager_kset->kobj);
++#endif
++
++ return 0;
++}
++
++static void __exit manager_exit(void)
++{
++ gb_audio_manager_remove_all();
++ kset_unregister(manager_kset);
++ ida_destroy(&module_id);
++}
++
++module_init(manager_init);
++module_exit(manager_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Svetlin Ankov <ankov_svetlin@projectara.com>");
+--- /dev/null
++++ b/drivers/greybus/audio_manager.h
+@@ -0,0 +1,83 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef _GB_AUDIO_MANAGER_H_
++#define _GB_AUDIO_MANAGER_H_
++
++#include <linux/kobject.h>
++#include <linux/list.h>
++
++#define GB_AUDIO_MANAGER_NAME "gb_audio_manager"
++#define GB_AUDIO_MANAGER_MODULE_NAME_LEN 64
++#define GB_AUDIO_MANAGER_MODULE_NAME_LEN_SSCANF "63"
++
++struct gb_audio_manager_module_descriptor {
++ char name[GB_AUDIO_MANAGER_MODULE_NAME_LEN];
++ int slot;
++ int vid;
++ int pid;
++ int cport;
++ unsigned int ip_devices;
++ unsigned int op_devices;
++};
++
++struct gb_audio_manager_module {
++ struct kobject kobj;
++ struct list_head list;
++ int id;
++ struct gb_audio_manager_module_descriptor desc;
++};
++
++/*
++ * Creates a new gb_audio_manager_module_descriptor, using the specified
++ * descriptor.
++ *
++ * Returns a negative result on error, or the id of the newly created module.
++ *
++ */
++int gb_audio_manager_add(struct gb_audio_manager_module_descriptor *desc);
++
++/*
++ * Removes a connected gb_audio_manager_module_descriptor for the specified ID.
++ *
++ * Returns zero on success, or a negative value on error.
++ */
++int gb_audio_manager_remove(int id);
++
++/*
++ * Removes all connected gb_audio_modules
++ *
++ * Returns zero on success, or a negative value on error.
++ */
++void gb_audio_manager_remove_all(void);
++
++/*
++ * Retrieves a gb_audio_manager_module_descriptor for the specified id.
++ * Returns the gb_audio_manager_module_descriptor structure,
++ * or NULL if there is no module with the specified ID.
++ */
++struct gb_audio_manager_module *gb_audio_manager_get_module(int id);
++
++/*
++ * Decreases the refcount of the module, obtained by the get function.
++ * Modules are removed via gb_audio_manager_remove
++ */
++void gb_audio_manager_put_module(struct gb_audio_manager_module *module);
++
++/*
++ * Dumps the module for the specified id
++ * Return 0 on success
++ */
++int gb_audio_manager_dump_module(int id);
++
++/*
++ * Dumps all connected modules
++ */
++void gb_audio_manager_dump_all(void);
++
++#endif /* _GB_AUDIO_MANAGER_H_ */
+--- /dev/null
++++ b/drivers/greybus/audio_manager_module.c
+@@ -0,0 +1,258 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/slab.h>
++
++#include "audio_manager.h"
++#include "audio_manager_private.h"
++
++#define to_gb_audio_module_attr(x) \
++ container_of(x, struct gb_audio_manager_module_attribute, attr)
++#define to_gb_audio_module(x) \
++ container_of(x, struct gb_audio_manager_module, kobj)
++
++struct gb_audio_manager_module_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr,
++ char *buf);
++ ssize_t (*store)(struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr,
++ const char *buf, size_t count);
++};
++
++static ssize_t gb_audio_module_attr_show(
++ struct kobject *kobj, struct attribute *attr, char *buf)
++{
++ struct gb_audio_manager_module_attribute *attribute;
++ struct gb_audio_manager_module *module;
++
++ attribute = to_gb_audio_module_attr(attr);
++ module = to_gb_audio_module(kobj);
++
++ if (!attribute->show)
++ return -EIO;
++
++ return attribute->show(module, attribute, buf);
++}
++
++static ssize_t gb_audio_module_attr_store(struct kobject *kobj,
++ struct attribute *attr,
++ const char *buf, size_t len)
++{
++ struct gb_audio_manager_module_attribute *attribute;
++ struct gb_audio_manager_module *module;
++
++ attribute = to_gb_audio_module_attr(attr);
++ module = to_gb_audio_module(kobj);
++
++ if (!attribute->store)
++ return -EIO;
++
++ return attribute->store(module, attribute, buf, len);
++}
++
++static const struct sysfs_ops gb_audio_module_sysfs_ops = {
++ .show = gb_audio_module_attr_show,
++ .store = gb_audio_module_attr_store,
++};
++
++static void gb_audio_module_release(struct kobject *kobj)
++{
++ struct gb_audio_manager_module *module = to_gb_audio_module(kobj);
++
++ pr_info("Destroying audio module #%d\n", module->id);
++ /* TODO -> delete from list */
++ kfree(module);
++}
++
++static ssize_t gb_audio_module_name_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%s", module->desc.name);
++}
++
++static struct gb_audio_manager_module_attribute gb_audio_module_name_attribute =
++ __ATTR(name, 0664, gb_audio_module_name_show, NULL);
++
++static ssize_t gb_audio_module_slot_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d", module->desc.slot);
++}
++
++static struct gb_audio_manager_module_attribute gb_audio_module_slot_attribute =
++ __ATTR(slot, 0664, gb_audio_module_slot_show, NULL);
++
++static ssize_t gb_audio_module_vid_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d", module->desc.vid);
++}
++
++static struct gb_audio_manager_module_attribute gb_audio_module_vid_attribute =
++ __ATTR(vid, 0664, gb_audio_module_vid_show, NULL);
++
++static ssize_t gb_audio_module_pid_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d", module->desc.pid);
++}
++
++static struct gb_audio_manager_module_attribute gb_audio_module_pid_attribute =
++ __ATTR(pid, 0664, gb_audio_module_pid_show, NULL);
++
++static ssize_t gb_audio_module_cport_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d", module->desc.cport);
++}
++
++static struct gb_audio_manager_module_attribute
++ gb_audio_module_cport_attribute =
++ __ATTR(cport, 0664, gb_audio_module_cport_show, NULL);
++
++static ssize_t gb_audio_module_ip_devices_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "0x%X", module->desc.ip_devices);
++}
++
++static struct gb_audio_manager_module_attribute
++ gb_audio_module_ip_devices_attribute =
++ __ATTR(ip_devices, 0664, gb_audio_module_ip_devices_show, NULL);
++
++static ssize_t gb_audio_module_op_devices_show(
++ struct gb_audio_manager_module *module,
++ struct gb_audio_manager_module_attribute *attr, char *buf)
++{
++ return sprintf(buf, "0x%X", module->desc.op_devices);
++}
++
++static struct gb_audio_manager_module_attribute
++ gb_audio_module_op_devices_attribute =
++ __ATTR(op_devices, 0664, gb_audio_module_op_devices_show, NULL);
++
++static struct attribute *gb_audio_module_default_attrs[] = {
++ &gb_audio_module_name_attribute.attr,
++ &gb_audio_module_slot_attribute.attr,
++ &gb_audio_module_vid_attribute.attr,
++ &gb_audio_module_pid_attribute.attr,
++ &gb_audio_module_cport_attribute.attr,
++ &gb_audio_module_ip_devices_attribute.attr,
++ &gb_audio_module_op_devices_attribute.attr,
++ NULL, /* need to NULL terminate the list of attributes */
++};
++
++static struct kobj_type gb_audio_module_type = {
++ .sysfs_ops = &gb_audio_module_sysfs_ops,
++ .release = gb_audio_module_release,
++ .default_attrs = gb_audio_module_default_attrs,
++};
++
++static void send_add_uevent(struct gb_audio_manager_module *module)
++{
++ char name_string[128];
++ char slot_string[64];
++ char vid_string[64];
++ char pid_string[64];
++ char cport_string[64];
++ char ip_devices_string[64];
++ char op_devices_string[64];
++
++ char *envp[] = {
++ name_string,
++ slot_string,
++ vid_string,
++ pid_string,
++ cport_string,
++ ip_devices_string,
++ op_devices_string,
++ NULL
++ };
++
++ snprintf(name_string, 128, "NAME=%s", module->desc.name);
++ snprintf(slot_string, 64, "SLOT=%d", module->desc.slot);
++ snprintf(vid_string, 64, "VID=%d", module->desc.vid);
++ snprintf(pid_string, 64, "PID=%d", module->desc.pid);
++ snprintf(cport_string, 64, "CPORT=%d", module->desc.cport);
++ snprintf(ip_devices_string, 64, "I/P DEVICES=0x%X",
++ module->desc.ip_devices);
++ snprintf(op_devices_string, 64, "O/P DEVICES=0x%X",
++ module->desc.op_devices);
++
++ kobject_uevent_env(&module->kobj, KOBJ_ADD, envp);
++}
++
++int gb_audio_manager_module_create(
++ struct gb_audio_manager_module **module,
++ struct kset *manager_kset,
++ int id, struct gb_audio_manager_module_descriptor *desc)
++{
++ int err;
++ struct gb_audio_manager_module *m;
++
++ m = kzalloc(sizeof(*m), GFP_ATOMIC);
++ if (!m)
++ return -ENOMEM;
++
++ /* Initialize the node */
++ INIT_LIST_HEAD(&m->list);
++
++ /* Set the module id */
++ m->id = id;
++
++ /* Copy the provided descriptor */
++ memcpy(&m->desc, desc, sizeof(*desc));
++
++ /* set the kset */
++ m->kobj.kset = manager_kset;
++
++ /*
++ * Initialize and add the kobject to the kernel. All the default files
++ * will be created here. As we have already specified a kset for this
++ * kobject, we don't have to set a parent for the kobject, the kobject
++ * will be placed beneath that kset automatically.
++ */
++ err = kobject_init_and_add(&m->kobj, &gb_audio_module_type, NULL, "%d",
++ id);
++ if (err) {
++ pr_err("failed initializing kobject for audio module #%d\n",
++ id);
++ kobject_put(&m->kobj);
++ return err;
++ }
++
++ /*
++ * Notify the object was created
++ */
++ send_add_uevent(m);
++
++ *module = m;
++ pr_info("Created audio module #%d\n", id);
++ return 0;
++}
++
++void gb_audio_manager_module_dump(struct gb_audio_manager_module *module)
++{
++ pr_info("audio module #%d name=%s slot=%d vid=%d pid=%d cport=%d i/p devices=0x%X o/p devices=0x%X\n",
++ module->id,
++ module->desc.name,
++ module->desc.slot,
++ module->desc.vid,
++ module->desc.pid,
++ module->desc.cport,
++ module->desc.ip_devices,
++ module->desc.op_devices);
++}
+--- /dev/null
++++ b/drivers/greybus/audio_manager_private.h
+@@ -0,0 +1,28 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef _GB_AUDIO_MANAGER_PRIVATE_H_
++#define _GB_AUDIO_MANAGER_PRIVATE_H_
++
++#include <linux/kobject.h>
++
++#include "audio_manager.h"
++
++int gb_audio_manager_module_create(
++ struct gb_audio_manager_module **module,
++ struct kset *manager_kset,
++ int id, struct gb_audio_manager_module_descriptor *desc);
++
++/* module destroyed via kobject_put */
++
++void gb_audio_manager_module_dump(struct gb_audio_manager_module *module);
++
++/* sysfs control */
++void gb_audio_manager_sysfs_init(struct kobject *kobj);
++
++#endif /* _GB_AUDIO_MANAGER_PRIVATE_H_ */
+--- /dev/null
++++ b/drivers/greybus/audio_manager_sysfs.c
+@@ -0,0 +1,102 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2015-2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/string.h>
++#include <linux/sysfs.h>
++
++#include "audio_manager.h"
++#include "audio_manager_private.h"
++
++static ssize_t manager_sysfs_add_store(
++ struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct gb_audio_manager_module_descriptor desc = { {0} };
++
++ int num = sscanf(buf,
++ "name=%" GB_AUDIO_MANAGER_MODULE_NAME_LEN_SSCANF "s "
++ "slot=%d vid=%d pid=%d cport=%d i/p devices=0x%X"
++ "o/p devices=0x%X",
++ desc.name, &desc.slot, &desc.vid, &desc.pid,
++ &desc.cport, &desc.ip_devices, &desc.op_devices);
++
++ if (num != 7)
++ return -EINVAL;
++
++ num = gb_audio_manager_add(&desc);
++ if (num < 0)
++ return -EINVAL;
++
++ return count;
++}
++
++static struct kobj_attribute manager_add_attribute =
++ __ATTR(add, 0664, NULL, manager_sysfs_add_store);
++
++static ssize_t manager_sysfs_remove_store(
++ struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int id;
++
++ int num = sscanf(buf, "%d", &id);
++
++ if (num != 1)
++ return -EINVAL;
++
++ num = gb_audio_manager_remove(id);
++ if (num)
++ return num;
++
++ return count;
++}
++
++static struct kobj_attribute manager_remove_attribute =
++ __ATTR(remove, 0664, NULL, manager_sysfs_remove_store);
++
++static ssize_t manager_sysfs_dump_store(
++ struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int id;
++
++ int num = sscanf(buf, "%d", &id);
++
++ if (num == 1) {
++ num = gb_audio_manager_dump_module(id);
++ if (num)
++ return num;
++ } else if (!strncmp("all", buf, 3))
++ gb_audio_manager_dump_all();
++ else
++ return -EINVAL;
++
++ return count;
++}
++
++static struct kobj_attribute manager_dump_attribute =
++ __ATTR(dump, 0664, NULL, manager_sysfs_dump_store);
++
++static void manager_sysfs_init_attribute(
++ struct kobject *kobj, struct kobj_attribute *kattr)
++{
++ int err;
++
++ err = sysfs_create_file(kobj, &kattr->attr);
++ if (err) {
++ pr_warn("creating the sysfs entry for %s failed: %d\n",
++ kattr->attr.name, err);
++ }
++}
++
++void gb_audio_manager_sysfs_init(struct kobject *kobj)
++{
++ manager_sysfs_init_attribute(kobj, &manager_add_attribute);
++ manager_sysfs_init_attribute(kobj, &manager_remove_attribute);
++ manager_sysfs_init_attribute(kobj, &manager_dump_attribute);
++}
+--- /dev/null
++++ b/drivers/greybus/audio_module.c
+@@ -0,0 +1,482 @@
++/*
++ * Greybus audio driver
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <sound/soc.h>
++#include <sound/pcm_params.h>
++
++#include "audio_codec.h"
++#include "audio_apbridgea.h"
++#include "audio_manager.h"
++
++/*
++ * gb_snd management functions
++ */
++
++static int gbaudio_request_jack(struct gbaudio_module_info *module,
++ struct gb_audio_jack_event_request *req)
++{
++ int report;
++ struct snd_jack *jack = module->headset_jack.jack;
++ struct snd_jack *btn_jack = module->button_jack.jack;
++
++ if (!jack) {
++ dev_err_ratelimited(module->dev,
++ "Invalid jack event received:type: %u, event: %u\n",
++ req->jack_attribute, req->event);
++ return -EINVAL;
++ }
++
++ dev_warn_ratelimited(module->dev,
++ "Jack Event received: type: %u, event: %u\n",
++ req->jack_attribute, req->event);
++
++ if (req->event == GB_AUDIO_JACK_EVENT_REMOVAL) {
++ module->jack_type = 0;
++ if (btn_jack && module->button_status) {
++ snd_soc_jack_report(&module->button_jack, 0,
++ module->button_mask);
++ module->button_status = 0;
++ }
++ snd_soc_jack_report(&module->headset_jack, 0,
++ module->jack_mask);
++ return 0;
++ }
++
++ report = req->jack_attribute & module->jack_mask;
++ if (!report) {
++ dev_err_ratelimited(module->dev,
++ "Invalid jack event received:type: %u, event: %u\n",
++ req->jack_attribute, req->event);
++ return -EINVAL;
++ }
++
++ if (module->jack_type)
++ dev_warn_ratelimited(module->dev,
++ "Modifying jack from %d to %d\n",
++ module->jack_type, report);
++
++ module->jack_type = report;
++ snd_soc_jack_report(&module->headset_jack, report, module->jack_mask);
++
++ return 0;
++}
++
++static int gbaudio_request_button(struct gbaudio_module_info *module,
++ struct gb_audio_button_event_request *req)
++{
++ int soc_button_id, report;
++ struct snd_jack *btn_jack = module->button_jack.jack;
++
++ if (!btn_jack) {
++ dev_err_ratelimited(module->dev,
++ "Invalid button event received:type: %u, event: %u\n",
++ req->button_id, req->event);
++ return -EINVAL;
++ }
++
++ dev_warn_ratelimited(module->dev,
++ "Button Event received: id: %u, event: %u\n",
++ req->button_id, req->event);
++
++ /* currently supports 4 buttons only */
++ if (!module->jack_type) {
++ dev_err_ratelimited(module->dev,
++ "Jack not present. Bogus event!!\n");
++ return -EINVAL;
++ }
++
++ report = module->button_status & module->button_mask;
++ soc_button_id = 0;
++
++ switch (req->button_id) {
++ case 1:
++ soc_button_id = SND_JACK_BTN_0 & module->button_mask;
++ break;
++
++ case 2:
++ soc_button_id = SND_JACK_BTN_1 & module->button_mask;
++ break;
++
++ case 3:
++ soc_button_id = SND_JACK_BTN_2 & module->button_mask;
++ break;
++
++ case 4:
++ soc_button_id = SND_JACK_BTN_3 & module->button_mask;
++ break;
++ }
++
++ if (!soc_button_id) {
++ dev_err_ratelimited(module->dev,
++ "Invalid button request received\n");
++ return -EINVAL;
++ }
++
++ if (req->event == GB_AUDIO_BUTTON_EVENT_PRESS)
++ report = report | soc_button_id;
++ else
++ report = report & ~soc_button_id;
++
++ module->button_status = report;
++
++ snd_soc_jack_report(&module->button_jack, report, module->button_mask);
++
++ return 0;
++}
++
++static int gbaudio_request_stream(struct gbaudio_module_info *module,
++ struct gb_audio_streaming_event_request *req)
++{
++ dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n",
++ req->data_cport, req->event);
++
++ return 0;
++}
++
++static int gbaudio_codec_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gbaudio_module_info *module =
++ greybus_get_drvdata(connection->bundle);
++ struct gb_operation_msg_hdr *header = op->request->header;
++ struct gb_audio_streaming_event_request *stream_req;
++ struct gb_audio_jack_event_request *jack_req;
++ struct gb_audio_button_event_request *button_req;
++ int ret;
++
++ switch (header->type) {
++ case GB_AUDIO_TYPE_STREAMING_EVENT:
++ stream_req = op->request->payload;
++ ret = gbaudio_request_stream(module, stream_req);
++ break;
++
++ case GB_AUDIO_TYPE_JACK_EVENT:
++ jack_req = op->request->payload;
++ ret = gbaudio_request_jack(module, jack_req);
++ break;
++
++ case GB_AUDIO_TYPE_BUTTON_EVENT:
++ button_req = op->request->payload;
++ ret = gbaudio_request_button(module, button_req);
++ break;
++
++ default:
++ dev_err_ratelimited(&connection->bundle->dev,
++ "Invalid Audio Event received\n");
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule,
++ struct greybus_descriptor_cport *cport_desc,
++ struct gb_bundle *bundle)
++{
++ struct gb_connection *connection;
++
++ /* Management Cport */
++ if (gbmodule->mgmt_connection) {
++ dev_err(&bundle->dev,
++ "Can't have multiple Management connections\n");
++ return -ENODEV;
++ }
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gbaudio_codec_request_handler);
++ if (IS_ERR(connection))
++ return PTR_ERR(connection);
++
++ greybus_set_drvdata(bundle, gbmodule);
++ gbmodule->mgmt_connection = connection;
++
++ return 0;
++}
++
++static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule,
++ struct greybus_descriptor_cport *cport_desc,
++ struct gb_bundle *bundle)
++{
++ struct gb_connection *connection;
++ struct gbaudio_data_connection *dai;
++
++ dai = devm_kzalloc(gbmodule->dev, sizeof(*dai), GFP_KERNEL);
++ if (!dai) {
++ dev_err(gbmodule->dev, "DAI Malloc failure\n");
++ return -ENOMEM;
++ }
++
++ connection = gb_connection_create_offloaded(bundle,
++ le16_to_cpu(cport_desc->id),
++ GB_CONNECTION_FLAG_CSD);
++ if (IS_ERR(connection)) {
++ devm_kfree(gbmodule->dev, dai);
++ return PTR_ERR(connection);
++ }
++
++ greybus_set_drvdata(bundle, gbmodule);
++ dai->id = 0;
++ dai->data_cport = connection->intf_cport_id;
++ dai->connection = connection;
++ list_add(&dai->list, &gbmodule->data_list);
++
++ return 0;
++}
++
++/*
++ * This is the basic hook get things initialized and registered w/ gb
++ */
++
++static int gb_audio_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct device *dev = &bundle->dev;
++ struct gbaudio_module_info *gbmodule;
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_audio_manager_module_descriptor desc;
++ struct gbaudio_data_connection *dai, *_dai;
++ int ret, i;
++ struct gb_audio_topology *topology;
++
++ /* There should be at least one Management and one Data cport */
++ if (bundle->num_cports < 2)
++ return -ENODEV;
++
++ /*
++ * There can be only one Management connection and any number of data
++ * connections.
++ */
++ gbmodule = devm_kzalloc(dev, sizeof(*gbmodule), GFP_KERNEL);
++ if (!gbmodule)
++ return -ENOMEM;
++
++ gbmodule->num_data_connections = bundle->num_cports - 1;
++ INIT_LIST_HEAD(&gbmodule->data_list);
++ INIT_LIST_HEAD(&gbmodule->widget_list);
++ INIT_LIST_HEAD(&gbmodule->ctl_list);
++ INIT_LIST_HEAD(&gbmodule->widget_ctl_list);
++ gbmodule->dev = dev;
++ snprintf(gbmodule->name, NAME_SIZE, "%s.%s", dev->driver->name,
++ dev_name(dev));
++ greybus_set_drvdata(bundle, gbmodule);
++
++ /* Create all connections */
++ for (i = 0; i < bundle->num_cports; i++) {
++ cport_desc = &bundle->cport_desc[i];
++
++ switch (cport_desc->protocol_id) {
++ case GREYBUS_PROTOCOL_AUDIO_MGMT:
++ ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc,
++ bundle);
++ if (ret)
++ goto destroy_connections;
++ break;
++ case GREYBUS_PROTOCOL_AUDIO_DATA:
++ ret = gb_audio_add_data_connection(gbmodule, cport_desc,
++ bundle);
++ if (ret)
++ goto destroy_connections;
++ break;
++ default:
++ dev_err(dev, "Unsupported protocol: 0x%02x\n",
++ cport_desc->protocol_id);
++ ret = -ENODEV;
++ goto destroy_connections;
++ }
++ }
++
++ /* There must be a management cport */
++ if (!gbmodule->mgmt_connection) {
++ ret = -EINVAL;
++ dev_err(dev, "Missing management connection\n");
++ goto destroy_connections;
++ }
++
++ /* Initialize management connection */
++ ret = gb_connection_enable(gbmodule->mgmt_connection);
++ if (ret) {
++ dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
++ goto destroy_connections;
++ }
++ gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id;
++
++ /*
++ * FIXME: malloc for topology happens via audio_gb driver
++ * should be done within codec driver itself
++ */
++ ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology);
++ if (ret) {
++ dev_err(dev, "%d:Error while fetching topology\n", ret);
++ goto disable_connection;
++ }
++
++ /* process topology data */
++ ret = gbaudio_tplg_parse_data(gbmodule, topology);
++ if (ret) {
++ dev_err(dev, "%d:Error while parsing topology data\n",
++ ret);
++ goto free_topology;
++ }
++ gbmodule->topology = topology;
++
++ /* Initialize data connections */
++ list_for_each_entry(dai, &gbmodule->data_list, list) {
++ ret = gb_connection_enable(dai->connection);
++ if (ret) {
++ dev_err(dev,
++ "%d:Error while enabling %d:data connection\n",
++ ret, dai->data_cport);
++ goto disable_data_connection;
++ }
++ }
++
++ /* register module with gbcodec */
++ ret = gbaudio_register_module(gbmodule);
++ if (ret)
++ goto disable_data_connection;
++
++ /* inform above layer for uevent */
++ dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
++ /* prepare for the audio manager */
++ strlcpy(desc.name, gbmodule->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN);
++ desc.slot = 1; /* todo */
++ desc.vid = 2; /* todo */
++ desc.pid = 3; /* todo */
++ desc.cport = gbmodule->dev_id;
++ desc.op_devices = gbmodule->op_devices;
++ desc.ip_devices = gbmodule->ip_devices;
++ gbmodule->manager_id = gb_audio_manager_add(&desc);
++
++ dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++disable_data_connection:
++ list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list)
++ gb_connection_disable(dai->connection);
++ gbaudio_tplg_release(gbmodule);
++ gbmodule->topology = NULL;
++
++free_topology:
++ kfree(topology);
++
++disable_connection:
++ gb_connection_disable(gbmodule->mgmt_connection);
++
++destroy_connections:
++ list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
++ gb_connection_destroy(dai->connection);
++ list_del(&dai->list);
++ devm_kfree(dev, dai);
++ }
++
++ if (gbmodule->mgmt_connection)
++ gb_connection_destroy(gbmodule->mgmt_connection);
++
++ devm_kfree(dev, gbmodule);
++
++ return ret;
++}
++
++static void gb_audio_disconnect(struct gb_bundle *bundle)
++{
++ struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
++ struct gbaudio_data_connection *dai, *_dai;
++
++ gb_pm_runtime_get_sync(bundle);
++
++ /* cleanup module related resources first */
++ gbaudio_unregister_module(gbmodule);
++
++ /* inform uevent to above layers */
++ gb_audio_manager_remove(gbmodule->manager_id);
++
++ gbaudio_tplg_release(gbmodule);
++ kfree(gbmodule->topology);
++ gbmodule->topology = NULL;
++ gb_connection_disable(gbmodule->mgmt_connection);
++ list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
++ gb_connection_disable(dai->connection);
++ gb_connection_destroy(dai->connection);
++ list_del(&dai->list);
++ devm_kfree(gbmodule->dev, dai);
++ }
++ gb_connection_destroy(gbmodule->mgmt_connection);
++ gbmodule->mgmt_connection = NULL;
++
++ devm_kfree(&bundle->dev, gbmodule);
++}
++
++static const struct greybus_bundle_id gb_audio_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
++
++#ifdef CONFIG_PM
++static int gb_audio_suspend(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
++ struct gbaudio_data_connection *dai;
++
++ list_for_each_entry(dai, &gbmodule->data_list, list)
++ gb_connection_disable(dai->connection);
++
++ gb_connection_disable(gbmodule->mgmt_connection);
++
++ return 0;
++}
++
++static int gb_audio_resume(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
++ struct gbaudio_data_connection *dai;
++ int ret;
++
++ ret = gb_connection_enable(gbmodule->mgmt_connection);
++ if (ret) {
++ dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
++ return ret;
++ }
++
++ list_for_each_entry(dai, &gbmodule->data_list, list) {
++ ret = gb_connection_enable(dai->connection);
++ if (ret) {
++ dev_err(dev,
++ "%d:Error while enabling %d:data connection\n",
++ ret, dai->data_cport);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops gb_audio_pm_ops = {
++ SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
++};
++
++static struct greybus_driver gb_audio_driver = {
++ .name = "gb-audio",
++ .probe = gb_audio_probe,
++ .disconnect = gb_audio_disconnect,
++ .id_table = gb_audio_id_table,
++ .driver.pm = &gb_audio_pm_ops,
++};
++module_greybus_driver(gb_audio_driver);
++
++MODULE_DESCRIPTION("Greybus Audio module driver");
++MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:gbaudio-module");
+--- /dev/null
++++ b/drivers/greybus/audio_topology.c
+@@ -0,0 +1,1442 @@
++/*
++ * Greybus audio driver
++ * Copyright 2015-2016 Google Inc.
++ * Copyright 2015-2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "audio_codec.h"
++#include "greybus_protocols.h"
++
++#define GBAUDIO_INVALID_ID 0xFF
++
++/* mixer control */
++struct gb_mixer_control {
++ int min, max;
++ unsigned int reg, rreg, shift, rshift, invert;
++};
++
++struct gbaudio_ctl_pvt {
++ unsigned int ctl_id;
++ unsigned int data_cport;
++ unsigned int access;
++ unsigned int vcount;
++ struct gb_audio_ctl_elem_info *info;
++};
++
++static struct gbaudio_module_info *find_gb_module(
++ struct gbaudio_codec_info *codec,
++ char const *name)
++{
++ int dev_id, ret;
++ char begin[NAME_SIZE];
++ struct gbaudio_module_info *module;
++
++ if (!name)
++ return NULL;
++
++ ret = sscanf(name, "%s %d", begin, &dev_id);
++ dev_dbg(codec->dev, "%s:Find module#%d\n", __func__, dev_id);
++
++ mutex_lock(&codec->lock);
++ list_for_each_entry(module, &codec->module_list, list) {
++ if (module->dev_id == dev_id) {
++ mutex_unlock(&codec->lock);
++ return module;
++ }
++ }
++ mutex_unlock(&codec->lock);
++ dev_warn(codec->dev, "%s: module#%d missing in codec list\n", name,
++ dev_id);
++ return NULL;
++}
++
++static const char *gbaudio_map_controlid(struct gbaudio_module_info *module,
++ __u8 control_id, __u8 index)
++{
++ struct gbaudio_control *control;
++
++ if (control_id == GBAUDIO_INVALID_ID)
++ return NULL;
++
++ list_for_each_entry(control, &module->ctl_list, list) {
++ if (control->id == control_id) {
++ if (index == GBAUDIO_INVALID_ID)
++ return control->name;
++ if (index >= control->items)
++ return NULL;
++ return control->texts[index];
++ }
++ }
++ list_for_each_entry(control, &module->widget_ctl_list, list) {
++ if (control->id == control_id) {
++ if (index == GBAUDIO_INVALID_ID)
++ return control->name;
++ if (index >= control->items)
++ return NULL;
++ return control->texts[index];
++ }
++ }
++ return NULL;
++}
++
++static int gbaudio_map_controlname(struct gbaudio_module_info *module,
++ const char *name)
++{
++ struct gbaudio_control *control;
++
++ list_for_each_entry(control, &module->ctl_list, list) {
++ if (!strncmp(control->name, name, NAME_SIZE))
++ return control->id;
++ }
++
++ dev_warn(module->dev, "%s: missing in modules controls list\n", name);
++
++ return -EINVAL;
++}
++
++static int gbaudio_map_wcontrolname(struct gbaudio_module_info *module,
++ const char *name)
++{
++ struct gbaudio_control *control;
++
++ list_for_each_entry(control, &module->widget_ctl_list, list) {
++ if (!strncmp(control->wname, name, NAME_SIZE))
++ return control->id;
++ }
++ dev_warn(module->dev, "%s: missing in modules controls list\n", name);
++
++ return -EINVAL;
++}
++
++static int gbaudio_map_widgetname(struct gbaudio_module_info *module,
++ const char *name)
++{
++ struct gbaudio_widget *widget;
++ list_for_each_entry(widget, &module->widget_list, list) {
++ if (!strncmp(widget->name, name, NAME_SIZE))
++ return widget->id;
++ }
++ dev_warn(module->dev, "%s: missing in modules widgets list\n", name);
++
++ return -EINVAL;
++}
++
++static const char *gbaudio_map_widgetid(struct gbaudio_module_info *module,
++ __u8 widget_id)
++{
++ struct gbaudio_widget *widget;
++
++ list_for_each_entry(widget, &module->widget_list, list) {
++ if (widget->id == widget_id)
++ return widget->name;
++ }
++ return NULL;
++}
++
++static const char **gb_generate_enum_strings(struct gbaudio_module_info *gb,
++ struct gb_audio_enumerated *gbenum)
++{
++ const char **strings;
++ int i;
++ __u8 *data;
++
++ strings = devm_kzalloc(gb->dev, sizeof(char *) * gbenum->items,
++ GFP_KERNEL);
++ data = gbenum->names;
++
++ for (i = 0; i < gbenum->items; i++) {
++ strings[i] = (const char *)data;
++ while (*data != '\0')
++ data++;
++ data++;
++ }
++
++ return strings;
++}
++
++static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ unsigned int max;
++ const char *name;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_info *info;
++ struct gbaudio_module_info *module;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++
++ if (!info) {
++ dev_err(module->dev, "NULL info for %s\n", uinfo->id.name);
++ return -EINVAL;
++ }
++
++ /* update uinfo */
++ uinfo->access = data->access;
++ uinfo->count = data->vcount;
++ uinfo->type = (snd_ctl_elem_type_t)info->type;
++
++ switch (info->type) {
++ case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
++ case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
++ uinfo->value.integer.min = info->value.integer.min;
++ uinfo->value.integer.max = info->value.integer.max;
++ break;
++ case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
++ max = info->value.enumerated.items;
++ uinfo->value.enumerated.items = max;
++ if (uinfo->value.enumerated.item > max - 1)
++ uinfo->value.enumerated.item = max - 1;
++ module = find_gb_module(gbcodec, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++ name = gbaudio_map_controlid(module, data->ctl_id,
++ uinfo->value.enumerated.item);
++ strlcpy(uinfo->value.enumerated.name, name, NAME_SIZE);
++ break;
++ default:
++ dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n",
++ info->type, kcontrol->id.name);
++ break;
++ }
++ return 0;
++}
++
++static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret;
++ struct gb_audio_ctl_elem_info *info;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ return ret;
++ }
++
++ /* update ucontrol */
++ switch (info->type) {
++ case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
++ case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
++ ucontrol->value.integer.value[0] =
++ gbvalue.value.integer_value[0];
++ if (data->vcount == 2)
++ ucontrol->value.integer.value[1] =
++ gbvalue.value.integer_value[1];
++ break;
++ case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
++ ucontrol->value.enumerated.item[0] =
++ gbvalue.value.enumerated_item[0];
++ if (data->vcount == 2)
++ ucontrol->value.enumerated.item[1] =
++ gbvalue.value.enumerated_item[1];
++ break;
++ default:
++ dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n",
++ info->type, kcontrol->id.name);
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret = 0;
++ struct gb_audio_ctl_elem_info *info;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++ bundle = to_gb_bundle(module->dev);
++
++ /* update ucontrol */
++ switch (info->type) {
++ case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
++ case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
++ gbvalue.value.integer_value[0] =
++ ucontrol->value.integer.value[0];
++ if (data->vcount == 2)
++ gbvalue.value.integer_value[1] =
++ ucontrol->value.integer.value[1];
++ break;
++ case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
++ gbvalue.value.enumerated_item[0] =
++ ucontrol->value.enumerated.item[0];
++ if (data->vcount == 2)
++ gbvalue.value.enumerated_item[1] =
++ ucontrol->value.enumerated.item[1];
++ break;
++ default:
++ dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n",
++ info->type, kcontrol->id.name);
++ ret = -EINVAL;
++ break;
++ }
++
++ if (ret)
++ return ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_set_control(module->mgmt_connection, data->ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ }
++
++ return ret;
++}
++
++#define SOC_MIXER_GB(xname, kcount, data) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++ .count = kcount, .info = gbcodec_mixer_ctl_info, \
++ .get = gbcodec_mixer_ctl_get, .put = gbcodec_mixer_ctl_put, \
++ .private_value = (unsigned long)data }
++
++/*
++ * although below callback functions seems redundant to above functions.
++ * same are kept to allow provision for different handling in case
++ * of DAPM related sequencing, etc.
++ */
++static int gbcodec_mixer_dapm_ctl_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ int platform_max, platform_min;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_info *info;
++ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
++ struct snd_soc_codec *codec = widget->codec;
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++
++ /* update uinfo */
++ platform_max = info->value.integer.max;
++ platform_min = info->value.integer.min;
++
++ if (platform_max == 1 &&
++ !strnstr(kcontrol->id.name, " Volume", NAME_SIZE))
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ else
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++
++ uinfo->count = data->vcount;
++ uinfo->value.integer.min = 0;
++ if (info->value.integer.min < 0 &&
++ (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER))
++ uinfo->value.integer.max = platform_max - platform_min;
++ else
++ uinfo->value.integer.max = platform_max;
++
++ return 0;
++}
++
++static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret;
++ struct gb_audio_ctl_elem_info *info;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
++ struct snd_soc_codec *codec = widget->codec;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++ bundle = to_gb_bundle(module->dev);
++
++ if (data->vcount == 2)
++ dev_warn(widget->dapm->dev,
++ "GB: Control '%s' is stereo, which is not supported\n",
++ kcontrol->id.name);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ return ret;
++ }
++ /* update ucontrol */
++ ucontrol->value.integer.value[0] = gbvalue.value.integer_value[0];
++
++ return ret;
++}
++
++static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret, wi, max, connect;
++ unsigned int mask, val;
++ struct gb_audio_ctl_elem_info *info;
++ struct gbaudio_ctl_pvt *data;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
++ struct snd_soc_codec *codec = widget->codec;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
++ info = (struct gb_audio_ctl_elem_info *)data->info;
++ bundle = to_gb_bundle(module->dev);
++
++ if (data->vcount == 2)
++ dev_warn(widget->dapm->dev,
++ "GB: Control '%s' is stereo, which is not supported\n",
++ kcontrol->id.name);
++
++ max = info->value.integer.max;
++ mask = (1 << fls(max)) - 1;
++ val = (ucontrol->value.integer.value[0] & mask);
++ connect = !!val;
++
++ /* update ucontrol */
++ if (gbvalue.value.integer_value[0] != val) {
++ for (wi = 0; wi < wlist->num_widgets; wi++) {
++ widget = wlist->widgets[wi];
++
++ widget->value = val;
++ widget->dapm->update = NULL;
++ snd_soc_dapm_mixer_update_power(widget, kcontrol,
++ connect);
++ }
++ gbvalue.value.integer_value[0] =
++ ucontrol->value.integer.value[0];
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_set_control(module->mgmt_connection,
++ data->ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev,
++ "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ }
++ }
++
++ return ret;
++}
++
++#define SOC_DAPM_MIXER_GB(xname, kcount, data) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++ .count = kcount, .info = gbcodec_mixer_dapm_ctl_info, \
++ .get = gbcodec_mixer_dapm_ctl_get, .put = gbcodec_mixer_dapm_ctl_put, \
++ .private_value = (unsigned long)data}
++
++static int gbcodec_event_spk(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *k, int event)
++{
++ /* Ensure GB speaker is connected */
++
++ return 0;
++}
++
++static int gbcodec_event_hp(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *k, int event)
++{
++ /* Ensure GB module supports jack slot */
++
++ return 0;
++}
++
++static int gbcodec_event_int_mic(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *k, int event)
++{
++ /* Ensure GB module supports jack slot */
++
++ return 0;
++}
++
++static int gbaudio_validate_kcontrol_count(struct gb_audio_widget *w)
++{
++ int ret = 0;
++
++ switch (w->type) {
++ case snd_soc_dapm_spk:
++ case snd_soc_dapm_hp:
++ case snd_soc_dapm_mic:
++ case snd_soc_dapm_output:
++ case snd_soc_dapm_input:
++ if (w->ncontrols)
++ ret = -EINVAL;
++ break;
++ case snd_soc_dapm_switch:
++ case snd_soc_dapm_mux:
++ if (w->ncontrols != 1)
++ ret = -EINVAL;
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int gbcodec_enum_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret, ctl_id;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ ctl_id = gbaudio_map_controlname(module, kcontrol->id.name);
++ if (ctl_id < 0)
++ return -EINVAL;
++
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ return ret;
++ }
++
++ ucontrol->value.enumerated.item[0] = gbvalue.value.enumerated_item[0];
++ if (e->shift_l != e->shift_r)
++ ucontrol->value.enumerated.item[1] =
++ gbvalue.value.enumerated_item[1];
++
++ return 0;
++}
++
++static int gbcodec_enum_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret, ctl_id;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct gb_bundle *bundle;
++
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ ctl_id = gbaudio_map_controlname(module, kcontrol->id.name);
++ if (ctl_id < 0)
++ return -EINVAL;
++
++ if (ucontrol->value.enumerated.item[0] > e->max - 1)
++ return -EINVAL;
++ gbvalue.value.enumerated_item[0] = ucontrol->value.enumerated.item[0];
++
++ if (e->shift_l != e->shift_r) {
++ if (ucontrol->value.enumerated.item[1] > e->max - 1)
++ return -EINVAL;
++ gbvalue.value.enumerated_item[1] =
++ ucontrol->value.enumerated.item[1];
++ }
++
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_set_control(module->mgmt_connection, ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ }
++
++ return ret;
++}
++
++static int gbaudio_tplg_create_enum_kctl(struct gbaudio_module_info *gb,
++ struct snd_kcontrol_new *kctl,
++ struct gb_audio_control *ctl)
++{
++ struct soc_enum *gbe;
++ struct gb_audio_enumerated *gb_enum;
++ int i;
++
++ gbe = devm_kzalloc(gb->dev, sizeof(*gbe), GFP_KERNEL);
++ if (!gbe)
++ return -ENOMEM;
++
++ gb_enum = &ctl->info.value.enumerated;
++
++ /* since count=1, and reg is dummy */
++ gbe->max = gb_enum->items;
++ gbe->texts = gb_generate_enum_strings(gb, gb_enum);
++
++ /* debug enum info */
++ dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gb_enum->items,
++ gb_enum->names_length);
++ for (i = 0; i < gb_enum->items; i++)
++ dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]);
++
++ *kctl = (struct snd_kcontrol_new)
++ SOC_ENUM_EXT(ctl->name, *gbe, gbcodec_enum_ctl_get,
++ gbcodec_enum_ctl_put);
++ return 0;
++}
++
++static int gbaudio_tplg_create_kcontrol(struct gbaudio_module_info *gb,
++ struct snd_kcontrol_new *kctl,
++ struct gb_audio_control *ctl)
++{
++ int ret = 0;
++ struct gbaudio_ctl_pvt *ctldata;
++
++ switch (ctl->iface) {
++ case SNDRV_CTL_ELEM_IFACE_MIXER:
++ switch (ctl->info.type) {
++ case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
++ ret = gbaudio_tplg_create_enum_kctl(gb, kctl, ctl);
++ break;
++ default:
++ ctldata = devm_kzalloc(gb->dev,
++ sizeof(struct gbaudio_ctl_pvt),
++ GFP_KERNEL);
++ if (!ctldata)
++ return -ENOMEM;
++ ctldata->ctl_id = ctl->id;
++ ctldata->data_cport = ctl->data_cport;
++ ctldata->access = ctl->access;
++ ctldata->vcount = ctl->count_values;
++ ctldata->info = &ctl->info;
++ *kctl = (struct snd_kcontrol_new)
++ SOC_MIXER_GB(ctl->name, ctl->count, ctldata);
++ ctldata = NULL;
++ break;
++ }
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ dev_dbg(gb->dev, "%s:%d control created\n", ctl->name, ctl->id);
++ return ret;
++}
++
++static int gbcodec_enum_dapm_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret, ctl_id;
++ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
++ struct gbaudio_module_info *module;
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct snd_soc_codec *codec = widget->codec;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++ struct gb_bundle *bundle;
++
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ ctl_id = gbaudio_map_wcontrolname(module, kcontrol->id.name);
++ if (ctl_id < 0)
++ return -EINVAL;
++
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ return ret;
++ }
++
++ ucontrol->value.enumerated.item[0] = gbvalue.value.enumerated_item[0];
++ if (e->shift_l != e->shift_r)
++ ucontrol->value.enumerated.item[1] =
++ gbvalue.value.enumerated_item[1];
++
++ return 0;
++}
++
++static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int ret, wi, ctl_id;
++ unsigned int val, mux, change;
++ unsigned int mask;
++ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
++ struct gb_audio_ctl_elem_value gbvalue;
++ struct gbaudio_module_info *module;
++ struct snd_soc_codec *codec = widget->codec;
++ struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++ struct gb_bundle *bundle;
++
++ if (ucontrol->value.enumerated.item[0] > e->max - 1)
++ return -EINVAL;
++
++ module = find_gb_module(gb, kcontrol->id.name);
++ if (!module)
++ return -EINVAL;
++
++ ctl_id = gbaudio_map_wcontrolname(module, kcontrol->id.name);
++ if (ctl_id < 0)
++ return -EINVAL;
++
++ change = 0;
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_get_control(module->mgmt_connection, ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ return ret;
++ }
++
++ mux = ucontrol->value.enumerated.item[0];
++ val = mux << e->shift_l;
++ mask = e->mask << e->shift_l;
++
++ if (gbvalue.value.enumerated_item[0] !=
++ ucontrol->value.enumerated.item[0]) {
++ change = 1;
++ gbvalue.value.enumerated_item[0] =
++ ucontrol->value.enumerated.item[0];
++ }
++
++ if (e->shift_l != e->shift_r) {
++ if (ucontrol->value.enumerated.item[1] > e->max - 1)
++ return -EINVAL;
++ val |= ucontrol->value.enumerated.item[1] << e->shift_r;
++ mask |= e->mask << e->shift_r;
++ if (gbvalue.value.enumerated_item[1] !=
++ ucontrol->value.enumerated.item[1]) {
++ change = 1;
++ gbvalue.value.enumerated_item[1] =
++ ucontrol->value.enumerated.item[1];
++ }
++ }
++
++ if (change) {
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_audio_gb_set_control(module->mgmt_connection, ctl_id,
++ GB_AUDIO_INVALID_INDEX, &gbvalue);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ if (ret) {
++ dev_err_ratelimited(codec->dev,
++ "%d:Error in %s for %s\n", ret,
++ __func__, kcontrol->id.name);
++ }
++ for (wi = 0; wi < wlist->num_widgets; wi++) {
++ widget = wlist->widgets[wi];
++
++ widget->value = val;
++ widget->dapm->update = NULL;
++ snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
++ }
++ }
++
++ return change;
++}
++
++static int gbaudio_tplg_create_enum_ctl(struct gbaudio_module_info *gb,
++ struct snd_kcontrol_new *kctl,
++ struct gb_audio_control *ctl)
++{
++ struct soc_enum *gbe;
++ struct gb_audio_enumerated *gb_enum;
++ int i;
++
++ gbe = devm_kzalloc(gb->dev, sizeof(*gbe), GFP_KERNEL);
++ if (!gbe)
++ return -ENOMEM;
++
++ gb_enum = &ctl->info.value.enumerated;
++
++ /* since count=1, and reg is dummy */
++ gbe->max = gb_enum->items;
++ gbe->texts = gb_generate_enum_strings(gb, gb_enum);
++
++ /* debug enum info */
++ dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gb_enum->items,
++ gb_enum->names_length);
++ for (i = 0; i < gb_enum->items; i++)
++ dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]);
++
++ *kctl = (struct snd_kcontrol_new)
++ SOC_DAPM_ENUM_EXT(ctl->name, *gbe, gbcodec_enum_dapm_ctl_get,
++ gbcodec_enum_dapm_ctl_put);
++ return 0;
++}
++
++static int gbaudio_tplg_create_mixer_ctl(struct gbaudio_module_info *gb,
++ struct snd_kcontrol_new *kctl,
++ struct gb_audio_control *ctl)
++{
++ struct gbaudio_ctl_pvt *ctldata;
++
++ ctldata = devm_kzalloc(gb->dev, sizeof(struct gbaudio_ctl_pvt),
++ GFP_KERNEL);
++ if (!ctldata)
++ return -ENOMEM;
++ ctldata->ctl_id = ctl->id;
++ ctldata->data_cport = ctl->data_cport;
++ ctldata->access = ctl->access;
++ ctldata->vcount = ctl->count_values;
++ ctldata->info = &ctl->info;
++ *kctl = (struct snd_kcontrol_new)
++ SOC_DAPM_MIXER_GB(ctl->name, ctl->count, ctldata);
++
++ return 0;
++}
++
++static int gbaudio_tplg_create_wcontrol(struct gbaudio_module_info *gb,
++ struct snd_kcontrol_new *kctl,
++ struct gb_audio_control *ctl)
++{
++ int ret;
++
++ switch (ctl->iface) {
++ case SNDRV_CTL_ELEM_IFACE_MIXER:
++ switch (ctl->info.type) {
++ case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
++ ret = gbaudio_tplg_create_enum_ctl(gb, kctl, ctl);
++ break;
++ default:
++ ret = gbaudio_tplg_create_mixer_ctl(gb, kctl, ctl);
++ break;
++ }
++ break;
++ default:
++ return -EINVAL;
++
++ }
++
++ dev_dbg(gb->dev, "%s:%d DAPM control created, ret:%d\n", ctl->name,
++ ctl->id, ret);
++ return ret;
++}
++
++static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *kcontrol, int event)
++{
++ int wid;
++ int ret;
++ struct snd_soc_codec *codec = w->codec;
++ struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
++ struct gbaudio_module_info *module;
++ struct gb_bundle *bundle;
++
++ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
++
++ /* Find relevant module */
++ module = find_gb_module(gbcodec, w->name);
++ if (!module)
++ return -EINVAL;
++
++ /* map name to widget id */
++ wid = gbaudio_map_widgetname(module, w->name);
++ if (wid < 0) {
++ dev_err(codec->dev, "Invalid widget name:%s\n", w->name);
++ return -EINVAL;
++ }
++
++ bundle = to_gb_bundle(module->dev);
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ switch (event) {
++ case SND_SOC_DAPM_PRE_PMU:
++ ret = gb_audio_gb_enable_widget(module->mgmt_connection, wid);
++ if (!ret)
++ ret = gbaudio_module_update(gbcodec, w, module, 1);
++ break;
++ case SND_SOC_DAPM_POST_PMD:
++ ret = gb_audio_gb_disable_widget(module->mgmt_connection, wid);
++ if (!ret)
++ ret = gbaudio_module_update(gbcodec, w, module, 0);
++ break;
++ }
++ if (ret)
++ dev_err_ratelimited(codec->dev,
++ "%d: widget, event:%d failed:%d\n", wid,
++ event, ret);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int gbaudio_tplg_create_widget(struct gbaudio_module_info *module,
++ struct snd_soc_dapm_widget *dw,
++ struct gb_audio_widget *w, int *w_size)
++{
++ int i, ret, csize;
++ struct snd_kcontrol_new *widget_kctls;
++ struct gb_audio_control *curr;
++ struct gbaudio_control *control, *_control;
++ size_t size;
++ char temp_name[NAME_SIZE];
++
++ ret = gbaudio_validate_kcontrol_count(w);
++ if (ret) {
++ dev_err(module->dev, "Inavlid kcontrol count=%d for %s\n",
++ w->ncontrols, w->name);
++ return ret;
++ }
++
++ /* allocate memory for kcontrol */
++ if (w->ncontrols) {
++ size = sizeof(struct snd_kcontrol_new) * w->ncontrols;
++ widget_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL);
++ if (!widget_kctls)
++ return -ENOMEM;
++ }
++
++ *w_size = sizeof(struct gb_audio_widget);
++
++ /* create relevant kcontrols */
++ curr = w->ctl;
++ for (i = 0; i < w->ncontrols; i++) {
++ ret = gbaudio_tplg_create_wcontrol(module, &widget_kctls[i],
++ curr);
++ if (ret) {
++ dev_err(module->dev,
++ "%s:%d type widget_ctl not supported\n",
++ curr->name, curr->iface);
++ goto error;
++ }
++ control = devm_kzalloc(module->dev,
++ sizeof(struct gbaudio_control),
++ GFP_KERNEL);
++ if (!control) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ control->id = curr->id;
++ control->name = curr->name;
++ control->wname = w->name;
++
++ if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED) {
++ struct gb_audio_enumerated *gbenum =
++ &curr->info.value.enumerated;
++
++ csize = offsetof(struct gb_audio_control, info);
++ csize += offsetof(struct gb_audio_ctl_elem_info, value);
++ csize += offsetof(struct gb_audio_enumerated, names);
++ csize += gbenum->names_length;
++ control->texts = (const char * const *)
++ gb_generate_enum_strings(module, gbenum);
++ control->items = gbenum->items;
++ } else
++ csize = sizeof(struct gb_audio_control);
++ *w_size += csize;
++ curr = (void *)curr + csize;
++ list_add(&control->list, &module->widget_ctl_list);
++ dev_dbg(module->dev, "%s: control of type %d created\n",
++ widget_kctls[i].name, widget_kctls[i].iface);
++ }
++
++ /* Prefix dev_id to widget control_name */
++ strlcpy(temp_name, w->name, NAME_SIZE);
++ snprintf(w->name, NAME_SIZE, "GB %d %s", module->dev_id, temp_name);
++
++ switch (w->type) {
++ case snd_soc_dapm_spk:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_SPK(w->name, gbcodec_event_spk);
++ module->op_devices |= GBAUDIO_DEVICE_OUT_SPEAKER;
++ break;
++ case snd_soc_dapm_hp:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_HP(w->name, gbcodec_event_hp);
++ module->op_devices |= (GBAUDIO_DEVICE_OUT_WIRED_HEADSET
++ | GBAUDIO_DEVICE_OUT_WIRED_HEADPHONE);
++ module->ip_devices |= GBAUDIO_DEVICE_IN_WIRED_HEADSET;
++ break;
++ case snd_soc_dapm_mic:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_MIC(w->name, gbcodec_event_int_mic);
++ module->ip_devices |= GBAUDIO_DEVICE_IN_BUILTIN_MIC;
++ break;
++ case snd_soc_dapm_output:
++ *dw = (struct snd_soc_dapm_widget)SND_SOC_DAPM_OUTPUT(w->name);
++ break;
++ case snd_soc_dapm_input:
++ *dw = (struct snd_soc_dapm_widget)SND_SOC_DAPM_INPUT(w->name);
++ break;
++ case snd_soc_dapm_switch:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_SWITCH_E(w->name, SND_SOC_NOPM, 0, 0,
++ widget_kctls, gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ case snd_soc_dapm_pga:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_PGA_E(w->name, SND_SOC_NOPM, 0, 0, NULL, 0,
++ gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ case snd_soc_dapm_mixer:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_MIXER_E(w->name, SND_SOC_NOPM, 0, 0, NULL,
++ 0, gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ case snd_soc_dapm_mux:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_MUX_E(w->name, SND_SOC_NOPM, 0, 0,
++ widget_kctls, gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ case snd_soc_dapm_aif_in:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_AIF_IN_E(w->name, w->sname, 0,
++ SND_SOC_NOPM,
++ 0, 0, gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ case snd_soc_dapm_aif_out:
++ *dw = (struct snd_soc_dapm_widget)
++ SND_SOC_DAPM_AIF_OUT_E(w->name, w->sname, 0,
++ SND_SOC_NOPM,
++ 0, 0, gbaudio_widget_event,
++ SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMD);
++ break;
++ default:
++ ret = -EINVAL;
++ goto error;
++ }
++
++ dev_dbg(module->dev, "%s: widget of type %d created\n", dw->name,
++ dw->id);
++ return 0;
++error:
++ list_for_each_entry_safe(control, _control, &module->widget_ctl_list,
++ list) {
++ list_del(&control->list);
++ devm_kfree(module->dev, control);
++ }
++ return ret;
++}
++
++static int gbaudio_tplg_process_kcontrols(struct gbaudio_module_info *module,
++ struct gb_audio_control *controls)
++{
++ int i, csize, ret;
++ struct snd_kcontrol_new *dapm_kctls;
++ struct gb_audio_control *curr;
++ struct gbaudio_control *control, *_control;
++ size_t size;
++ char temp_name[NAME_SIZE];
++
++ size = sizeof(struct snd_kcontrol_new) * module->num_controls;
++ dapm_kctls = devm_kzalloc(module->dev, size, GFP_KERNEL);
++ if (!dapm_kctls)
++ return -ENOMEM;
++
++ curr = controls;
++ for (i = 0; i < module->num_controls; i++) {
++ ret = gbaudio_tplg_create_kcontrol(module, &dapm_kctls[i],
++ curr);
++ if (ret) {
++ dev_err(module->dev, "%s:%d type not supported\n",
++ curr->name, curr->iface);
++ goto error;
++ }
++ control = devm_kzalloc(module->dev, sizeof(struct
++ gbaudio_control),
++ GFP_KERNEL);
++ if (!control) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ control->id = curr->id;
++ /* Prefix dev_id to widget_name */
++ strlcpy(temp_name, curr->name, NAME_SIZE);
++ snprintf(curr->name, NAME_SIZE, "GB %d %s", module->dev_id,
++ temp_name);
++ control->name = curr->name;
++ if (curr->info.type == GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED) {
++ struct gb_audio_enumerated *gbenum =
++ &curr->info.value.enumerated;
++
++ csize = offsetof(struct gb_audio_control, info);
++ csize += offsetof(struct gb_audio_ctl_elem_info, value);
++ csize += offsetof(struct gb_audio_enumerated, names);
++ csize += gbenum->names_length;
++ control->texts = (const char * const *)
++ gb_generate_enum_strings(module, gbenum);
++ control->items = gbenum->items;
++ } else
++ csize = sizeof(struct gb_audio_control);
++
++ list_add(&control->list, &module->ctl_list);
++ dev_dbg(module->dev, "%d:%s created of type %d\n", curr->id,
++ curr->name, curr->info.type);
++ curr = (void *)curr + csize;
++ }
++ module->controls = dapm_kctls;
++
++ return 0;
++error:
++ list_for_each_entry_safe(control, _control, &module->ctl_list,
++ list) {
++ list_del(&control->list);
++ devm_kfree(module->dev, control);
++ }
++ devm_kfree(module->dev, dapm_kctls);
++ return ret;
++}
++
++static int gbaudio_tplg_process_widgets(struct gbaudio_module_info *module,
++ struct gb_audio_widget *widgets)
++{
++ int i, ret, w_size;
++ struct snd_soc_dapm_widget *dapm_widgets;
++ struct gb_audio_widget *curr;
++ struct gbaudio_widget *widget, *_widget;
++ size_t size;
++
++ size = sizeof(struct snd_soc_dapm_widget) * module->num_dapm_widgets;
++ dapm_widgets = devm_kzalloc(module->dev, size, GFP_KERNEL);
++ if (!dapm_widgets)
++ return -ENOMEM;
++
++ curr = widgets;
++ for (i = 0; i < module->num_dapm_widgets; i++) {
++ ret = gbaudio_tplg_create_widget(module, &dapm_widgets[i],
++ curr, &w_size);
++ if (ret) {
++ dev_err(module->dev, "%s:%d type not supported\n",
++ curr->name, curr->type);
++ goto error;
++ }
++ widget = devm_kzalloc(module->dev, sizeof(struct
++ gbaudio_widget),
++ GFP_KERNEL);
++ if (!widget) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ widget->id = curr->id;
++ widget->name = curr->name;
++ list_add(&widget->list, &module->widget_list);
++ curr = (void *)curr + w_size;
++ }
++ module->dapm_widgets = dapm_widgets;
++
++ return 0;
++
++error:
++ list_for_each_entry_safe(widget, _widget, &module->widget_list,
++ list) {
++ list_del(&widget->list);
++ devm_kfree(module->dev, widget);
++ }
++ devm_kfree(module->dev, dapm_widgets);
++ return ret;
++}
++
++static int gbaudio_tplg_process_routes(struct gbaudio_module_info *module,
++ struct gb_audio_route *routes)
++{
++ int i, ret;
++ struct snd_soc_dapm_route *dapm_routes;
++ struct gb_audio_route *curr;
++ size_t size;
++
++ size = sizeof(struct snd_soc_dapm_route) * module->num_dapm_routes;
++ dapm_routes = devm_kzalloc(module->dev, size, GFP_KERNEL);
++ if (!dapm_routes)
++ return -ENOMEM;
++
++ module->dapm_routes = dapm_routes;
++ curr = routes;
++
++ for (i = 0; i < module->num_dapm_routes; i++) {
++ dapm_routes->sink =
++ gbaudio_map_widgetid(module, curr->destination_id);
++ if (!dapm_routes->sink) {
++ dev_err(module->dev, "%d:%d:%d:%d - Invalid sink\n",
++ curr->source_id, curr->destination_id,
++ curr->control_id, curr->index);
++ ret = -EINVAL;
++ goto error;
++ }
++ dapm_routes->source =
++ gbaudio_map_widgetid(module, curr->source_id);
++ if (!dapm_routes->source) {
++ dev_err(module->dev, "%d:%d:%d:%d - Invalid source\n",
++ curr->source_id, curr->destination_id,
++ curr->control_id, curr->index);
++ ret = -EINVAL;
++ goto error;
++ }
++ dapm_routes->control =
++ gbaudio_map_controlid(module,
++ curr->control_id,
++ curr->index);
++ if ((curr->control_id != GBAUDIO_INVALID_ID) &&
++ !dapm_routes->control) {
++ dev_err(module->dev, "%d:%d:%d:%d - Invalid control\n",
++ curr->source_id, curr->destination_id,
++ curr->control_id, curr->index);
++ ret = -EINVAL;
++ goto error;
++ }
++ dev_dbg(module->dev, "Route {%s, %s, %s}\n", dapm_routes->sink,
++ (dapm_routes->control) ? dapm_routes->control:"NULL",
++ dapm_routes->source);
++ dapm_routes++;
++ curr++;
++ }
++
++ return 0;
++
++error:
++ devm_kfree(module->dev, module->dapm_routes);
++ return ret;
++}
++
++static int gbaudio_tplg_process_header(struct gbaudio_module_info *module,
++ struct gb_audio_topology *tplg_data)
++{
++ /* fetch no. of kcontrols, widgets & routes */
++ module->num_controls = tplg_data->num_controls;
++ module->num_dapm_widgets = tplg_data->num_widgets;
++ module->num_dapm_routes = tplg_data->num_routes;
++
++ /* update block offset */
++ module->dai_offset = (unsigned long)&tplg_data->data;
++ module->control_offset = module->dai_offset + tplg_data->size_dais;
++ module->widget_offset = module->control_offset +
++ tplg_data->size_controls;
++ module->route_offset = module->widget_offset +
++ tplg_data->size_widgets;
++
++ dev_dbg(module->dev, "DAI offset is 0x%lx\n", module->dai_offset);
++ dev_dbg(module->dev, "control offset is %lx\n",
++ module->control_offset);
++ dev_dbg(module->dev, "widget offset is %lx\n", module->widget_offset);
++ dev_dbg(module->dev, "route offset is %lx\n", module->route_offset);
++
++ return 0;
++}
++
++int gbaudio_tplg_parse_data(struct gbaudio_module_info *module,
++ struct gb_audio_topology *tplg_data)
++{
++ int ret;
++ struct gb_audio_control *controls;
++ struct gb_audio_widget *widgets;
++ struct gb_audio_route *routes;
++
++ if (!tplg_data)
++ return -EINVAL;
++
++ ret = gbaudio_tplg_process_header(module, tplg_data);
++ if (ret) {
++ dev_err(module->dev, "%d: Error in parsing topology header\n",
++ ret);
++ return ret;
++ }
++
++ /* process control */
++ controls = (struct gb_audio_control *)module->control_offset;
++ ret = gbaudio_tplg_process_kcontrols(module, controls);
++ if (ret) {
++ dev_err(module->dev,
++ "%d: Error in parsing controls data\n", ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Control parsing finished\n");
++
++ /* process widgets */
++ widgets = (struct gb_audio_widget *)module->widget_offset;
++ ret = gbaudio_tplg_process_widgets(module, widgets);
++ if (ret) {
++ dev_err(module->dev,
++ "%d: Error in parsing widgets data\n", ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Widget parsing finished\n");
++
++ /* process route */
++ routes = (struct gb_audio_route *)module->route_offset;
++ ret = gbaudio_tplg_process_routes(module, routes);
++ if (ret) {
++ dev_err(module->dev,
++ "%d: Error in parsing routes data\n", ret);
++ return ret;
++ }
++ dev_dbg(module->dev, "Route parsing finished\n");
++
++ /* parse jack capabilities */
++ if (tplg_data->jack_type) {
++ module->jack_mask = tplg_data->jack_type & GBCODEC_JACK_MASK;
++ module->button_mask = tplg_data->jack_type &
++ GBCODEC_JACK_BUTTON_MASK;
++ }
++
++ return ret;
++}
++
++void gbaudio_tplg_release(struct gbaudio_module_info *module)
++{
++ struct gbaudio_control *control, *_control;
++ struct gbaudio_widget *widget, *_widget;
++
++ if (!module->topology)
++ return;
++
++ /* release kcontrols */
++ list_for_each_entry_safe(control, _control, &module->ctl_list,
++ list) {
++ list_del(&control->list);
++ devm_kfree(module->dev, control);
++ }
++ if (module->controls)
++ devm_kfree(module->dev, module->controls);
++
++ /* release widget controls */
++ list_for_each_entry_safe(control, _control, &module->widget_ctl_list,
++ list) {
++ list_del(&control->list);
++ devm_kfree(module->dev, control);
++ }
++
++ /* release widgets */
++ list_for_each_entry_safe(widget, _widget, &module->widget_list,
++ list) {
++ list_del(&widget->list);
++ devm_kfree(module->dev, widget);
++ }
++ if (module->dapm_widgets)
++ devm_kfree(module->dev, module->dapm_widgets);
++
++ /* release routes */
++ if (module->dapm_routes)
++ devm_kfree(module->dev, module->dapm_routes);
++}
diff --git a/greybus_bootrom.patch b/greybus_bootrom.patch
new file mode 100644
index 00000000000000..b93f2267e3bada
--- /dev/null
+++ b/greybus_bootrom.patch
@@ -0,0 +1,531 @@
+---
+ drivers/greybus/bootrom.c | 524 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 524 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/bootrom.c
+@@ -0,0 +1,524 @@
++/*
++ * BOOTROM Greybus driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/firmware.h>
++#include <linux/jiffies.h>
++#include <linux/mutex.h>
++#include <linux/workqueue.h>
++
++#include "greybus.h"
++#include "firmware.h"
++
++/* Timeout, in jiffies, within which the next request must be received */
++#define NEXT_REQ_TIMEOUT_MS 1000
++
++/*
++ * FIXME: Reduce this timeout once svc core handles parallel processing of
++ * events from the SVC, which are handled sequentially today.
++ */
++#define MODE_SWITCH_TIMEOUT_MS 10000
++
++enum next_request_type {
++ NEXT_REQ_FIRMWARE_SIZE,
++ NEXT_REQ_GET_FIRMWARE,
++ NEXT_REQ_READY_TO_BOOT,
++ NEXT_REQ_MODE_SWITCH,
++};
++
++struct gb_bootrom {
++ struct gb_connection *connection;
++ const struct firmware *fw;
++ u8 protocol_major;
++ u8 protocol_minor;
++ enum next_request_type next_request;
++ struct delayed_work dwork;
++ struct mutex mutex; /* Protects bootrom->fw */
++};
++
++static void free_firmware(struct gb_bootrom *bootrom)
++{
++ if (!bootrom->fw)
++ return;
++
++ release_firmware(bootrom->fw);
++ bootrom->fw = NULL;
++}
++
++static void gb_bootrom_timedout(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct gb_bootrom *bootrom = container_of(dwork, struct gb_bootrom, dwork);
++ struct device *dev = &bootrom->connection->bundle->dev;
++ const char *reason;
++
++ switch (bootrom->next_request) {
++ case NEXT_REQ_FIRMWARE_SIZE:
++ reason = "Firmware Size Request";
++ break;
++ case NEXT_REQ_GET_FIRMWARE:
++ reason = "Get Firmware Request";
++ break;
++ case NEXT_REQ_READY_TO_BOOT:
++ reason = "Ready to Boot Request";
++ break;
++ case NEXT_REQ_MODE_SWITCH:
++ reason = "Interface Mode Switch";
++ break;
++ default:
++ reason = NULL;
++ dev_err(dev, "Invalid next-request: %u", bootrom->next_request);
++ break;
++ }
++
++ dev_err(dev, "Timed out waiting for %s from the Module\n", reason);
++
++ mutex_lock(&bootrom->mutex);
++ free_firmware(bootrom);
++ mutex_unlock(&bootrom->mutex);
++
++ /* TODO: Power-off Module ? */
++}
++
++static void gb_bootrom_set_timeout(struct gb_bootrom *bootrom,
++ enum next_request_type next, unsigned long timeout)
++{
++ bootrom->next_request = next;
++ schedule_delayed_work(&bootrom->dwork, msecs_to_jiffies(timeout));
++}
++
++static void gb_bootrom_cancel_timeout(struct gb_bootrom *bootrom)
++{
++ cancel_delayed_work_sync(&bootrom->dwork);
++}
++
++/*
++ * The es2 chip doesn't have VID/PID programmed into the hardware and we need to
++ * hack that up to distinguish different modules and their firmware blobs.
++ *
++ * This fetches VID/PID (over bootrom protocol) for es2 chip only, when VID/PID
++ * already sent during hotplug are 0.
++ *
++ * Otherwise, we keep intf->vendor_id/product_id same as what's passed
++ * during hotplug.
++ */
++static void bootrom_es2_fixup_vid_pid(struct gb_bootrom *bootrom)
++{
++ struct gb_bootrom_get_vid_pid_response response;
++ struct gb_connection *connection = bootrom->connection;
++ struct gb_interface *intf = connection->bundle->intf;
++ int ret;
++
++ if (!(intf->quirks & GB_INTERFACE_QUIRK_NO_GMP_IDS))
++ return;
++
++ ret = gb_operation_sync(connection, GB_BOOTROM_TYPE_GET_VID_PID,
++ NULL, 0, &response, sizeof(response));
++ if (ret) {
++ dev_err(&connection->bundle->dev,
++ "Bootrom get vid/pid operation failed (%d)\n", ret);
++ return;
++ }
++
++ /*
++ * NOTE: This is hacked, so that the same values of VID/PID can be used
++ * by next firmware level as well. The uevent for bootrom will still
++ * have VID/PID as 0, though after this point the sysfs files will start
++ * showing the updated values. But yeah, that's a bit racy as the same
++ * sysfs files would be showing 0 before this point.
++ */
++ intf->vendor_id = le32_to_cpu(response.vendor_id);
++ intf->product_id = le32_to_cpu(response.product_id);
++
++ dev_dbg(&connection->bundle->dev, "Bootrom got vid (0x%x)/pid (0x%x)\n",
++ intf->vendor_id, intf->product_id);
++}
++
++/* This returns path of the firmware blob on the disk */
++static int find_firmware(struct gb_bootrom *bootrom, u8 stage)
++{
++ struct gb_connection *connection = bootrom->connection;
++ struct gb_interface *intf = connection->bundle->intf;
++ char firmware_name[49];
++ int rc;
++
++ /* Already have a firmware, free it */
++ free_firmware(bootrom);
++
++ /* Bootrom protocol is only supported for loading Stage 2 firmware */
++ if (stage != 2) {
++ dev_err(&connection->bundle->dev, "Invalid boot stage: %u\n",
++ stage);
++ return -EINVAL;
++ }
++
++ /*
++ * Create firmware name
++ *
++ * XXX Name it properly..
++ */
++ snprintf(firmware_name, sizeof(firmware_name),
++ FW_NAME_PREFIX "%08x_%08x_%08x_%08x_s2l.tftf",
++ intf->ddbl1_manufacturer_id, intf->ddbl1_product_id,
++ intf->vendor_id, intf->product_id);
++
++ // FIXME:
++ // Turn to dev_dbg later after everyone has valid bootloaders with good
++ // ids, but leave this as dev_info for now to make it easier to track
++ // down "empty" vid/pid modules.
++ dev_info(&connection->bundle->dev, "Firmware file '%s' requested\n",
++ firmware_name);
++
++ rc = request_firmware(&bootrom->fw, firmware_name,
++ &connection->bundle->dev);
++ if (rc) {
++ dev_err(&connection->bundle->dev,
++ "failed to find %s firmware (%d)\n", firmware_name, rc);
++ }
++
++ return rc;
++}
++
++static int gb_bootrom_firmware_size_request(struct gb_operation *op)
++{
++ struct gb_bootrom *bootrom = gb_connection_get_data(op->connection);
++ struct gb_bootrom_firmware_size_request *size_request = op->request->payload;
++ struct gb_bootrom_firmware_size_response *size_response;
++ struct device *dev = &op->connection->bundle->dev;
++ int ret;
++
++ /* Disable timeouts */
++ gb_bootrom_cancel_timeout(bootrom);
++
++ if (op->request->payload_size != sizeof(*size_request)) {
++ dev_err(dev, "%s: illegal size of firmware size request (%zu != %zu)\n",
++ __func__, op->request->payload_size,
++ sizeof(*size_request));
++ ret = -EINVAL;
++ goto queue_work;
++ }
++
++ mutex_lock(&bootrom->mutex);
++
++ ret = find_firmware(bootrom, size_request->stage);
++ if (ret)
++ goto unlock;
++
++ if (!gb_operation_response_alloc(op, sizeof(*size_response),
++ GFP_KERNEL)) {
++ dev_err(dev, "%s: error allocating response\n", __func__);
++ free_firmware(bootrom);
++ ret = -ENOMEM;
++ goto unlock;
++ }
++
++ size_response = op->response->payload;
++ size_response->size = cpu_to_le32(bootrom->fw->size);
++
++ dev_dbg(dev, "%s: firmware size %d bytes\n", __func__, size_response->size);
++
++unlock:
++ mutex_unlock(&bootrom->mutex);
++
++queue_work:
++ if (!ret) {
++ /* Refresh timeout */
++ gb_bootrom_set_timeout(bootrom, NEXT_REQ_GET_FIRMWARE,
++ NEXT_REQ_TIMEOUT_MS);
++ }
++
++ return ret;
++}
++
++static int gb_bootrom_get_firmware(struct gb_operation *op)
++{
++ struct gb_bootrom *bootrom = gb_connection_get_data(op->connection);
++ const struct firmware *fw;
++ struct gb_bootrom_get_firmware_request *firmware_request;
++ struct gb_bootrom_get_firmware_response *firmware_response;
++ struct device *dev = &op->connection->bundle->dev;
++ unsigned int offset, size;
++ enum next_request_type next_request;
++ int ret = 0;
++
++ /* Disable timeouts */
++ gb_bootrom_cancel_timeout(bootrom);
++
++ if (op->request->payload_size != sizeof(*firmware_request)) {
++ dev_err(dev, "%s: Illegal size of get firmware request (%zu %zu)\n",
++ __func__, op->request->payload_size,
++ sizeof(*firmware_request));
++ ret = -EINVAL;
++ goto queue_work;
++ }
++
++ mutex_lock(&bootrom->mutex);
++
++ fw = bootrom->fw;
++ if (!fw) {
++ dev_err(dev, "%s: firmware not available\n", __func__);
++ ret = -EINVAL;
++ goto unlock;
++ }
++
++ firmware_request = op->request->payload;
++ offset = le32_to_cpu(firmware_request->offset);
++ size = le32_to_cpu(firmware_request->size);
++
++ if (offset >= fw->size || size > fw->size - offset) {
++ dev_warn(dev, "bad firmware request (offs = %u, size = %u)\n",
++ offset, size);
++ ret = -EINVAL;
++ goto unlock;
++ }
++
++ if (!gb_operation_response_alloc(op, sizeof(*firmware_response) + size,
++ GFP_KERNEL)) {
++ dev_err(dev, "%s: error allocating response\n", __func__);
++ ret = -ENOMEM;
++ goto unlock;
++ }
++
++ firmware_response = op->response->payload;
++ memcpy(firmware_response->data, fw->data + offset, size);
++
++ dev_dbg(dev, "responding with firmware (offs = %u, size = %u)\n", offset,
++ size);
++
++unlock:
++ mutex_unlock(&bootrom->mutex);
++
++queue_work:
++ /* Refresh timeout */
++ if (!ret && (offset + size == fw->size))
++ next_request = NEXT_REQ_READY_TO_BOOT;
++ else
++ next_request = NEXT_REQ_GET_FIRMWARE;
++
++ gb_bootrom_set_timeout(bootrom, next_request, NEXT_REQ_TIMEOUT_MS);
++
++ return ret;
++}
++
++static int gb_bootrom_ready_to_boot(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_bootrom *bootrom = gb_connection_get_data(connection);
++ struct gb_bootrom_ready_to_boot_request *rtb_request;
++ struct device *dev = &connection->bundle->dev;
++ u8 status;
++ int ret = 0;
++
++ /* Disable timeouts */
++ gb_bootrom_cancel_timeout(bootrom);
++
++ if (op->request->payload_size != sizeof(*rtb_request)) {
++ dev_err(dev, "%s: Illegal size of ready to boot request (%zu %zu)\n",
++ __func__, op->request->payload_size,
++ sizeof(*rtb_request));
++ ret = -EINVAL;
++ goto queue_work;
++ }
++
++ rtb_request = op->request->payload;
++ status = rtb_request->status;
++
++ /* Return error if the blob was invalid */
++ if (status == GB_BOOTROM_BOOT_STATUS_INVALID) {
++ ret = -EINVAL;
++ goto queue_work;
++ }
++
++ /*
++ * XXX Should we return error for insecure firmware?
++ */
++ dev_dbg(dev, "ready to boot: 0x%x, 0\n", status);
++
++queue_work:
++ /*
++ * Refresh timeout, the Interface shall load the new personality and
++ * send a new hotplug request, which shall get rid of the bootrom
++ * connection. As that can take some time, increase the timeout a bit.
++ */
++ gb_bootrom_set_timeout(bootrom, NEXT_REQ_MODE_SWITCH,
++ MODE_SWITCH_TIMEOUT_MS);
++
++ return ret;
++}
++
++static int gb_bootrom_request_handler(struct gb_operation *op)
++{
++ u8 type = op->type;
++
++ switch (type) {
++ case GB_BOOTROM_TYPE_FIRMWARE_SIZE:
++ return gb_bootrom_firmware_size_request(op);
++ case GB_BOOTROM_TYPE_GET_FIRMWARE:
++ return gb_bootrom_get_firmware(op);
++ case GB_BOOTROM_TYPE_READY_TO_BOOT:
++ return gb_bootrom_ready_to_boot(op);
++ default:
++ dev_err(&op->connection->bundle->dev,
++ "unsupported request: %u\n", type);
++ return -EINVAL;
++ }
++}
++
++static int gb_bootrom_get_version(struct gb_bootrom *bootrom)
++{
++ struct gb_bundle *bundle = bootrom->connection->bundle;
++ struct gb_bootrom_version_request request;
++ struct gb_bootrom_version_response response;
++ int ret;
++
++ request.major = GB_BOOTROM_VERSION_MAJOR;
++ request.minor = GB_BOOTROM_VERSION_MINOR;
++
++ ret = gb_operation_sync(bootrom->connection,
++ GB_BOOTROM_TYPE_VERSION,
++ &request, sizeof(request), &response,
++ sizeof(response));
++ if (ret) {
++ dev_err(&bundle->dev,
++ "failed to get protocol version: %d\n",
++ ret);
++ return ret;
++ }
++
++ if (response.major > request.major) {
++ dev_err(&bundle->dev,
++ "unsupported major protocol version (%u > %u)\n",
++ response.major, request.major);
++ return -ENOTSUPP;
++ }
++
++ bootrom->protocol_major = response.major;
++ bootrom->protocol_minor = response.minor;
++
++ dev_dbg(&bundle->dev, "%s - %u.%u\n", __func__, response.major,
++ response.minor);
++
++ return 0;
++}
++
++static int gb_bootrom_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_bootrom *bootrom;
++ int ret;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_BOOTROM)
++ return -ENODEV;
++
++ bootrom = kzalloc(sizeof(*bootrom), GFP_KERNEL);
++ if (!bootrom)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle,
++ le16_to_cpu(cport_desc->id),
++ gb_bootrom_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto err_free_bootrom;
++ }
++
++ gb_connection_set_data(connection, bootrom);
++
++ bootrom->connection = connection;
++
++ mutex_init(&bootrom->mutex);
++ INIT_DELAYED_WORK(&bootrom->dwork, gb_bootrom_timedout);
++ greybus_set_drvdata(bundle, bootrom);
++
++ ret = gb_connection_enable_tx(connection);
++ if (ret)
++ goto err_connection_destroy;
++
++ ret = gb_bootrom_get_version(bootrom);
++ if (ret)
++ goto err_connection_disable;
++
++ bootrom_es2_fixup_vid_pid(bootrom);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto err_connection_disable;
++
++ /* Refresh timeout */
++ gb_bootrom_set_timeout(bootrom, NEXT_REQ_FIRMWARE_SIZE,
++ NEXT_REQ_TIMEOUT_MS);
++
++ /* Tell bootrom we're ready. */
++ ret = gb_operation_sync(connection, GB_BOOTROM_TYPE_AP_READY, NULL, 0,
++ NULL, 0);
++ if (ret) {
++ dev_err(&connection->bundle->dev,
++ "failed to send AP READY: %d\n", ret);
++ goto err_cancel_timeout;
++ }
++
++ dev_dbg(&bundle->dev, "AP_READY sent\n");
++
++ return 0;
++
++err_cancel_timeout:
++ gb_bootrom_cancel_timeout(bootrom);
++err_connection_disable:
++ gb_connection_disable(connection);
++err_connection_destroy:
++ gb_connection_destroy(connection);
++err_free_bootrom:
++ kfree(bootrom);
++
++ return ret;
++}
++
++static void gb_bootrom_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_bootrom *bootrom = greybus_get_drvdata(bundle);
++
++ dev_dbg(&bundle->dev, "%s\n", __func__);
++
++ gb_connection_disable(bootrom->connection);
++
++ /* Disable timeouts */
++ gb_bootrom_cancel_timeout(bootrom);
++
++ /*
++ * Release firmware:
++ *
++ * As the connection and the delayed work are already disabled, we don't
++ * need to lock access to bootrom->fw here.
++ */
++ free_firmware(bootrom);
++
++ gb_connection_destroy(bootrom->connection);
++ kfree(bootrom);
++}
++
++static const struct greybus_bundle_id gb_bootrom_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BOOTROM) },
++ { }
++};
++
++static struct greybus_driver gb_bootrom_driver = {
++ .name = "bootrom",
++ .probe = gb_bootrom_probe,
++ .disconnect = gb_bootrom_disconnect,
++ .id_table = gb_bootrom_id_table,
++};
++
++module_greybus_driver(gb_bootrom_driver);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_build.patch b/greybus_build.patch
new file mode 100644
index 00000000000000..a06d8f7f199f0e
--- /dev/null
+++ b/greybus_build.patch
@@ -0,0 +1,344 @@
+---
+ drivers/Kconfig | 2
+ drivers/Makefile | 1
+ drivers/greybus/Kconfig | 219 +++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/Makefile | 96 ++++++++++++++++++++
+ 4 files changed, 318 insertions(+)
+
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconf
+
+ source "drivers/fpga/Kconfig"
+
++source "drivers/greybus/Kconfig"
++
+ endmenu
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -173,3 +173,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
+ obj-$(CONFIG_ANDROID) += android/
+ obj-$(CONFIG_NVMEM) += nvmem/
+ obj-$(CONFIG_FPGA) += fpga/
++obj-$(CONFIG_GREYBUS) += greybus/
+--- /dev/null
++++ b/drivers/greybus/Kconfig
+@@ -0,0 +1,219 @@
++menuconfig GREYBUS
++ tristate "Greybus support"
++ depends on SYSFS
++ ---help---
++ This option enables the Greybus driver core. Greybus is an
++ hardware protocol that was designed to provide Unipro with a
++ sane application layer. It was originally designed for the
++ ARA project, a module phone system, but has shown up in other
++ phones, and can be tunneled over other busses in order to
++ control hardware devices.
++
++ Say Y here to enable support for these types of drivers.
++
++ To compile this code as a module, chose M here: the module
++ will be called greybus.ko
++
++if GREYBUS
++
++config GREYBUS_ES2
++ tristate "Greybus ES3 USB host controller"
++ depends on USB
++ ---help---
++ Select this option if you have a Toshiba ES3 USB device that
++ acts as a Greybus "host controller". This device is a bridge
++ from a USB device to a Unipro network.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-es2.ko
++
++config GREYBUS_AUDIO
++ tristate "Greybus Audio Class driver"
++ depends on SOUND
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Audio Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-audio.ko
++
++config GREYBUS_BOOTROM
++ tristate "Greybus Bootrom Class driver"
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Bootrom Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-bootrom.ko
++
++config GREYBUS_CAMERA
++ tristate "Greybus Camera Class driver"
++ depends on MEDIA && LEDS_CLASS_FLASH && BROKEN
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Camera Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-camera.ko
++
++config GREYBUS_FIRMWARE
++ tristate "Greybus Firmware Download Class driver"
++ depends on SPI
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Firmware Download Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-firmware.ko
++
++config GREYBUS_HID
++ tristate "Greybus HID Class driver"
++ depends on HID && INPUT
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus HID Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-hid.ko
++
++config GREYBUS_LIGHT
++ tristate "Greybus LED Class driver"
++ depends on LEDS_CLASS
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus LED Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-light.ko
++
++config GREYBUS_LOG
++ tristate "Greybus Debug Log Class driver"
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Debug Log Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-log.ko
++
++config GREYBUS_LOOPBACK
++ tristate "Greybus Loopback Class driver"
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Debug Log Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-log.ko
++
++config GREYBUS_POWER
++ tristate "Greybus Powersupply Class driver"
++ depends on POWER_SUPPLY
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Powersupply Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-power-supply.ko
++
++config GREYBUS_RAW
++ tristate "Greybus Raw Class driver"
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Raw Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-raw.ko
++
++config GREYBUS_VIBRATOR
++ tristate "Greybus Vibrator Motor Class driver"
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus Vibrator Motor Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-vibrator.ko
++
++menuconfig GREYBUS_BRIDGED_PHY
++ tristate "Greybus Bridged PHY Class drivers"
++ ---help---
++ Select this option to pick from a variety of Greybus Bridged
++ PHY class drivers. These drivers emulate a number of
++ different "traditional" busses by tunneling them over Greybus.
++ Examples of this include serial, SPI, USB, and others.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-phy.ko
++
++if GREYBUS_BRIDGED_PHY
++
++config GREYBUS_GPIO
++ tristate "Greybus GPIO Bridged PHY driver"
++ depends on GPIO
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus GPIO Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-gpio.ko
++
++config GREYBUS_I2C
++ tristate "Greybus I2C Bridged PHY driver"
++ depends on I2C
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus I2C Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-i2c.ko
++
++config GREYBUS_PWM
++ tristate "Greybus PWM Bridged PHY driver"
++ depends on PWM
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus PWM Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-pwm.ko
++
++config GREYBUS_SDIO
++ tristate "Greybus SDIO Bridged PHY driver"
++ depends on MMC
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus SDIO Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-sdio.ko
++
++config GREYBUS_SPI
++ tristate "Greybus SPI Bridged PHY driver"
++ depends on SPI
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus SPI Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-spi.ko
++
++config GREYBUS_UART
++ tristate "Greybus UART Bridged PHY driver"
++ depends on TTY
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus UART Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-uart.ko
++
++config GREYBUS_USB
++ tristate "Greybus USB Host Bridged PHY driver"
++ depends on USB
++ ---help---
++ Select this option if you have a device that follows the
++ Greybus USB Host Bridged PHY Class specification.
++
++ To compile this code as a module, chose M here: the module
++ will be called gb-usb.ko
++
++endif # GREYBUS_BRIDGED_PHY
++endif # GREYBUS
+--- /dev/null
++++ b/drivers/greybus/Makefile
+@@ -0,0 +1,96 @@
++# Greybus core
++greybus-y := core.o \
++ debugfs.o \
++ hd.o \
++ manifest.o \
++ module.o \
++ interface.o \
++ bundle.o \
++ connection.o \
++ control.o \
++ svc.o \
++ svc_watchdog.o \
++ operation.o \
++ timesync.o \
++ timesync_platform.o
++
++obj-$(CONFIG_GREYBUS) += greybus.o
++
++# needed for trace events
++ccflags-y += -I$(src)
++
++
++# Greybus Host controller drivers
++gb-es2-y := es2.o
++
++obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o
++
++# Greybus class drivers
++gb-bootrom-y := bootrom.o
++gb-camera-y := camera.o
++gb-firmware-y := fw-core.o fw-download.o fw-management.o authentication.o
++gb-spilib-y := spilib.o
++gb-hid-y := hid.o
++gb-light-y := light.o
++gb-log-y := log.o
++gb-loopback-y := loopback.o
++gb-power-supply-y := power_supply.o
++gb-raw-y := raw.o
++gb-vibrator-y := vibrator.o
++
++obj-$(CONFIG_GREYBUS_BOOTROM) += gb-bootrom.o
++obj-$(CONFIG_GREYBUS_CAMERA) += gb-camera.o
++obj-$(CONFIG_GREYBUS_FIRMWARE) += gb-firmware.o gb-spilib.o
++obj-$(CONFIG_GREYBUS_HID) += gb-hid.o
++obj-$(CONFIG_GREYBUS_LIGHT) += gb-light.o
++obj-$(CONFIG_GREYBUS_LOG) += gb-log.o
++obj-$(CONFIG_GREYBUS_LOOPBACK) += gb-loopback.o
++obj-$(CONFIG_GREYBUS_POWER) += gb-power-supply.o
++obj-$(CONFIG_GREYBUS_RAW) += gb-raw.o
++obj-$(CONFIG_GREYBUS_VIBRATOR) += gb-vibrator.o
++
++# Greybus Audio is a bunch of modules
++gb-audio-module-y := audio_module.o audio_topology.o
++gb-audio-codec-y := audio_codec.o
++gb-audio-gb-y := audio_gb.o
++gb-audio-apbridgea-y := audio_apbridgea.o
++gb-audio-manager-y := audio_manager.o audio_manager_module.o
++
++# Greybus Audio sysfs helpers can be useful when debugging
++#GB_AUDIO_MANAGER_SYSFS ?= true
++#ifeq ($(GB_AUDIO_MANAGER_SYSFS),true)
++#gb-audio-manager-y += audio_manager_sysfs.o
++#ccflags-y += -DGB_AUDIO_MANAGER_SYSFS
++#endif
++
++obj-$(CONFIG_GREYBUS_AUDIO_MSM8994) += gb-audio-codec.o
++obj-$(CONFIG_GREYBUS_AUDIO_MSM8994) += gb-audio-module.o
++obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-gb.o
++obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-apbridgea.o
++obj-$(CONFIG_GREYBUS_AUDIO) += gb-audio-manager.o
++
++
++# Greybus Bridged PHY drivers
++gb-gbphy-y := gbphy.o
++gb-gpio-y := gpio.o
++gb-i2c-y := i2c.o
++gb-pwm-y := pwm.o
++gb-sdio-y := sdio.o
++gb-spi-y := spi.o
++gb-uart-y := uart.o
++gb-usb-y := usb.o
++
++obj-$(CONFIG_GREYBUS_BRIDGED_PHY) += gb-gbphy.o
++obj-$(CONFIG_GREYBUS_GPIO) += gb-gpio.o
++obj-$(CONFIG_GREYBUS_I2C) += gb-i2c.o
++obj-$(CONFIG_GREYBUS_PWM) += gb-pwm.o
++obj-$(CONFIG_GREYBUS_SDIO) += gb-sdio.o
++obj-$(CONFIG_GREYBUS_SPI) += gb-spi.o gb-spilib.o
++obj-$(CONFIG_GREYBUS_UART) += gb-uart.o
++obj-$(CONFIG_GREYBUS_USB) += gb-usb.o
++
++
++# Greybus Platform driver
++gb-arche-y := arche-platform.o arche-apb-ctrl.o
++
++obj-$(CONFIG_USB_HSIC_USB3613) += gb-arche.o
diff --git a/greybus_camera.patch b/greybus_camera.patch
new file mode 100644
index 00000000000000..0900dd1bf85672
--- /dev/null
+++ b/greybus_camera.patch
@@ -0,0 +1,1538 @@
+---
+ drivers/greybus/camera.c | 1400 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/gb-camera.h | 127 +++
+ 2 files changed, 1527 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/camera.c
+@@ -0,0 +1,1400 @@
++/*
++ * Greybus Camera protocol driver.
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/debugfs.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/uaccess.h>
++#include <linux/vmalloc.h>
++
++#include "gb-camera.h"
++#include "greybus.h"
++#include "greybus_protocols.h"
++
++enum gb_camera_debugs_buffer_id {
++ GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES,
++ GB_CAMERA_DEBUGFS_BUFFER_STREAMS,
++ GB_CAMERA_DEBUGFS_BUFFER_CAPTURE,
++ GB_CAMERA_DEBUGFS_BUFFER_FLUSH,
++ GB_CAMERA_DEBUGFS_BUFFER_MAX,
++};
++
++struct gb_camera_debugfs_buffer {
++ char data[PAGE_SIZE];
++ size_t length;
++};
++
++enum gb_camera_state {
++ GB_CAMERA_STATE_UNCONFIGURED,
++ GB_CAMERA_STATE_CONFIGURED,
++};
++
++/**
++ * struct gb_camera - A Greybus Camera Device
++ * @connection: the greybus connection for camera management
++ * @data_connection: the greybus connection for camera data
++ * @data_cport_id: the data CPort ID on the module side
++ * @mutex: protects the connection and state fields
++ * @state: the current module state
++ * @debugfs: debugfs entries for camera protocol operations testing
++ * @module: Greybus camera module registered to HOST processor.
++ */
++struct gb_camera {
++ struct gb_bundle *bundle;
++ struct gb_connection *connection;
++ struct gb_connection *data_connection;
++ u16 data_cport_id;
++
++ struct mutex mutex;
++ enum gb_camera_state state;
++
++ struct {
++ struct dentry *root;
++ struct gb_camera_debugfs_buffer *buffers;
++ } debugfs;
++
++ struct gb_camera_module module;
++};
++
++struct gb_camera_stream_config {
++ unsigned int width;
++ unsigned int height;
++ unsigned int format;
++ unsigned int vc;
++ unsigned int dt[2];
++ unsigned int max_size;
++};
++
++struct gb_camera_fmt_info {
++ enum v4l2_mbus_pixelcode mbus_code;
++ unsigned int gb_format;
++ unsigned int bpp;
++};
++
++/* GB format to media code map */
++static const struct gb_camera_fmt_info gb_fmt_info[] = {
++ {
++ .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16,
++ .gb_format = 0x01,
++ .bpp = 16,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_NV12_1x8,
++ .gb_format = 0x12,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_NV21_1x8,
++ .gb_format = 0x13,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_YU12_1x8,
++ .gb_format = 0x16,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_YV12_1x8,
++ .gb_format = 0x17,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_JPEG_1X8,
++ .gb_format = 0x40,
++ .bpp = 0,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_GB_CAM_METADATA_1X8,
++ .gb_format = 0x41,
++ .bpp = 0,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_GB_CAM_DEBUG_DATA_1X8,
++ .gb_format = 0x42,
++ .bpp = 0,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SBGGR10_1X10,
++ .gb_format = 0x80,
++ .bpp = 10,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SGBRG10_1X10,
++ .gb_format = 0x81,
++ .bpp = 10,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
++ .gb_format = 0x82,
++ .bpp = 10,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SRGGB10_1X10,
++ .gb_format = 0x83,
++ .bpp = 10,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12,
++ .gb_format = 0x84,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SGBRG12_1X12,
++ .gb_format = 0x85,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
++ .gb_format = 0x86,
++ .bpp = 12,
++ },
++ {
++ .mbus_code = V4L2_MBUS_FMT_SRGGB12_1X12,
++ .gb_format = 0x87,
++ .bpp = 12,
++ },
++};
++
++static const struct gb_camera_fmt_info *gb_camera_get_format_info(u16 gb_fmt)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) {
++ if (gb_fmt_info[i].gb_format == gb_fmt)
++ return &gb_fmt_info[i];
++ }
++
++ return NULL;
++}
++
++#define ES2_APB_CDSI0_CPORT 16
++#define ES2_APB_CDSI1_CPORT 17
++
++#define GB_CAMERA_MAX_SETTINGS_SIZE 8192
++
++#define gcam_dbg(gcam, format...) dev_dbg(&gcam->bundle->dev, format)
++#define gcam_info(gcam, format...) dev_info(&gcam->bundle->dev, format)
++#define gcam_err(gcam, format...) dev_err(&gcam->bundle->dev, format)
++
++static int gb_camera_operation_sync_flags(struct gb_connection *connection,
++ int type, unsigned int flags,
++ void *request, size_t request_size,
++ void *response, size_t *response_size)
++{
++ struct gb_operation *operation;
++ int ret;
++
++ operation = gb_operation_create_flags(connection, type, request_size,
++ *response_size, flags,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ if (request_size)
++ memcpy(operation->request->payload, request, request_size);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: synchronous operation of type 0x%02x failed: %d\n",
++ connection->name, type, ret);
++ } else {
++ *response_size = operation->response->payload_size;
++
++ if (operation->response->payload_size)
++ memcpy(response, operation->response->payload,
++ operation->response->payload_size);
++ }
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static int gb_camera_get_max_pkt_size(struct gb_camera *gcam,
++ struct gb_camera_configure_streams_response *resp)
++{
++ unsigned int max_pkt_size = 0;
++ unsigned int i;
++
++ for (i = 0; i < resp->num_streams; i++) {
++ struct gb_camera_stream_config_response *cfg = &resp->config[i];
++ const struct gb_camera_fmt_info *fmt_info;
++ unsigned int pkt_size;
++
++ fmt_info = gb_camera_get_format_info(cfg->format);
++ if (!fmt_info) {
++ gcam_err(gcam, "unsupported greybus image format: %d\n",
++ cfg->format);
++ return -EIO;
++ }
++
++ if (fmt_info->bpp == 0) {
++ pkt_size = le32_to_cpu(cfg->max_pkt_size);
++
++ if (pkt_size == 0) {
++ gcam_err(gcam,
++ "Stream %u: invalid zero maximum packet size\n",
++ i);
++ return -EIO;
++ }
++ } else {
++ pkt_size = le16_to_cpu(cfg->width) * fmt_info->bpp / 8;
++
++ if (pkt_size != le32_to_cpu(cfg->max_pkt_size)) {
++ gcam_err(gcam,
++ "Stream %u: maximum packet size mismatch (%u/%u)\n",
++ i, pkt_size, cfg->max_pkt_size);
++ return -EIO;
++ }
++ }
++
++ max_pkt_size = max(pkt_size, max_pkt_size);
++ }
++
++ return max_pkt_size;
++}
++
++/*
++ * Validate the stream configuration response verifying padding is correctly
++ * set and the returned number of streams is supported
++ */
++static const int gb_camera_configure_streams_validate_response(
++ struct gb_camera *gcam,
++ struct gb_camera_configure_streams_response *resp,
++ unsigned int nstreams)
++{
++ unsigned int i;
++
++ /* Validate the returned response structure */
++ if (resp->padding[0] || resp->padding[1]) {
++ gcam_err(gcam, "response padding != 0\n");
++ return -EIO;
++ }
++
++ if (resp->num_streams > nstreams) {
++ gcam_err(gcam, "got #streams %u > request %u\n",
++ resp->num_streams, nstreams);
++ return -EIO;
++ }
++
++ for (i = 0; i < resp->num_streams; i++) {
++ struct gb_camera_stream_config_response *cfg = &resp->config[i];
++ if (cfg->padding) {
++ gcam_err(gcam, "stream #%u padding != 0\n", i);
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
++
++/* -----------------------------------------------------------------------------
++ * Hardware Configuration
++ */
++
++static int gb_camera_set_intf_power_mode(struct gb_camera *gcam, u8 intf_id,
++ bool hs)
++{
++ struct gb_svc *svc = gcam->connection->hd->svc;
++ int ret;
++
++ if (hs)
++ ret = gb_svc_intf_set_power_mode(svc, intf_id,
++ GB_SVC_UNIPRO_HS_SERIES_A,
++ GB_SVC_UNIPRO_FAST_MODE, 2, 2,
++ GB_SVC_SMALL_AMPLITUDE,
++ GB_SVC_NO_DE_EMPHASIS,
++ GB_SVC_UNIPRO_FAST_MODE, 2, 2,
++ GB_SVC_PWRM_RXTERMINATION |
++ GB_SVC_PWRM_TXTERMINATION, 0,
++ NULL, NULL);
++ else
++ ret = gb_svc_intf_set_power_mode(svc, intf_id,
++ GB_SVC_UNIPRO_HS_SERIES_A,
++ GB_SVC_UNIPRO_SLOW_AUTO_MODE,
++ 2, 1,
++ GB_SVC_SMALL_AMPLITUDE,
++ GB_SVC_NO_DE_EMPHASIS,
++ GB_SVC_UNIPRO_SLOW_AUTO_MODE,
++ 2, 1,
++ 0, 0,
++ NULL, NULL);
++
++ return ret;
++}
++
++static int gb_camera_set_power_mode(struct gb_camera *gcam, bool hs)
++{
++ struct gb_interface *intf = gcam->connection->intf;
++ struct gb_svc *svc = gcam->connection->hd->svc;
++ int ret;
++
++ ret = gb_camera_set_intf_power_mode(gcam, intf->interface_id, hs);
++ if (ret < 0) {
++ gcam_err(gcam, "failed to set module interface to %s (%d)\n",
++ hs ? "HS" : "PWM", ret);
++ return ret;
++ }
++
++ ret = gb_camera_set_intf_power_mode(gcam, svc->ap_intf_id, hs);
++ if (ret < 0) {
++ gb_camera_set_intf_power_mode(gcam, intf->interface_id, !hs);
++ gcam_err(gcam, "failed to set AP interface to %s (%d)\n",
++ hs ? "HS" : "PWM", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++struct ap_csi_config_request {
++ __u8 csi_id;
++ __u8 flags;
++#define GB_CAMERA_CSI_FLAG_CLOCK_CONTINUOUS 0x01
++ __u8 num_lanes;
++ __u8 padding;
++ __le32 csi_clk_freq;
++ __le32 max_pkt_size;
++} __packed;
++
++/*
++ * TODO: Compute the number of lanes dynamically based on bandwidth
++ * requirements.
++ */
++#define GB_CAMERA_CSI_NUM_DATA_LANES 4
++
++#define GB_CAMERA_CSI_CLK_FREQ_MAX 999000000U
++#define GB_CAMERA_CSI_CLK_FREQ_MIN 100000000U
++#define GB_CAMERA_CSI_CLK_FREQ_MARGIN 150000000U
++
++static int gb_camera_setup_data_connection(struct gb_camera *gcam,
++ struct gb_camera_configure_streams_response *resp,
++ struct gb_camera_csi_params *csi_params)
++{
++ struct ap_csi_config_request csi_cfg;
++ struct gb_connection *conn;
++ unsigned int clk_freq;
++ int ret;
++
++ /*
++ * Create the data connection between the camera module data CPort and
++ * APB CDSI1. The CDSI1 CPort ID is hardcoded by the ES2 bridge.
++ */
++ conn = gb_connection_create_offloaded(gcam->bundle, gcam->data_cport_id,
++ GB_CONNECTION_FLAG_NO_FLOWCTRL |
++ GB_CONNECTION_FLAG_CDSI1);
++ if (IS_ERR(conn))
++ return PTR_ERR(conn);
++
++ gcam->data_connection = conn;
++ gb_connection_set_data(conn, gcam);
++
++ ret = gb_connection_enable(conn);
++ if (ret)
++ goto error_conn_destroy;
++
++ /* Set the UniPro link to high speed mode. */
++ ret = gb_camera_set_power_mode(gcam, true);
++ if (ret < 0)
++ goto error_conn_disable;
++
++ /*
++ * Configure the APB-A CSI-2 transmitter.
++ *
++ * Hardcode the number of lanes to 4 and compute the bus clock frequency
++ * based on the module bandwidth requirements with a safety margin.
++ */
++ memset(&csi_cfg, 0, sizeof(csi_cfg));
++ csi_cfg.csi_id = 1;
++ csi_cfg.flags = 0;
++ csi_cfg.num_lanes = GB_CAMERA_CSI_NUM_DATA_LANES;
++
++ clk_freq = resp->data_rate / 2 / GB_CAMERA_CSI_NUM_DATA_LANES;
++ clk_freq = clamp(clk_freq + GB_CAMERA_CSI_CLK_FREQ_MARGIN,
++ GB_CAMERA_CSI_CLK_FREQ_MIN,
++ GB_CAMERA_CSI_CLK_FREQ_MAX);
++ csi_cfg.csi_clk_freq = clk_freq;
++
++ ret = gb_camera_get_max_pkt_size(gcam, resp);
++ if (ret < 0) {
++ ret = -EIO;
++ goto error_power;
++ }
++ csi_cfg.max_pkt_size = ret;
++
++ ret = gb_hd_output(gcam->connection->hd, &csi_cfg,
++ sizeof(csi_cfg),
++ GB_APB_REQUEST_CSI_TX_CONTROL, false);
++ if (ret < 0) {
++ gcam_err(gcam, "failed to start the CSI transmitter\n");
++ goto error_power;
++ }
++
++ if (csi_params) {
++ csi_params->clk_freq = csi_cfg.csi_clk_freq;
++ csi_params->num_lanes = csi_cfg.num_lanes;
++ }
++
++ return 0;
++
++error_power:
++ gb_camera_set_power_mode(gcam, false);
++error_conn_disable:
++ gb_connection_disable(gcam->data_connection);
++error_conn_destroy:
++ gb_connection_destroy(gcam->data_connection);
++ gcam->data_connection = NULL;
++ return ret;
++}
++
++static void gb_camera_teardown_data_connection(struct gb_camera *gcam)
++{
++ struct ap_csi_config_request csi_cfg;
++ int ret;
++
++ /* Stop the APB1 CSI transmitter. */
++ memset(&csi_cfg, 0, sizeof(csi_cfg));
++ csi_cfg.csi_id = 1;
++
++ ret = gb_hd_output(gcam->connection->hd, &csi_cfg,
++ sizeof(csi_cfg),
++ GB_APB_REQUEST_CSI_TX_CONTROL, false);
++
++ if (ret < 0)
++ gcam_err(gcam, "failed to stop the CSI transmitter\n");
++
++ /* Set the UniPro link to low speed mode. */
++ gb_camera_set_power_mode(gcam, false);
++
++ /* Destroy the data connection. */
++ gb_connection_disable(gcam->data_connection);
++ gb_connection_destroy(gcam->data_connection);
++ gcam->data_connection = NULL;
++}
++
++/* -----------------------------------------------------------------------------
++ * Camera Protocol Operations
++ */
++
++static int gb_camera_capabilities(struct gb_camera *gcam,
++ u8 *capabilities, size_t *size)
++{
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(gcam->bundle);
++ if (ret)
++ return ret;
++
++ mutex_lock(&gcam->mutex);
++
++ if (!gcam->connection) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = gb_camera_operation_sync_flags(gcam->connection,
++ GB_CAMERA_TYPE_CAPABILITIES,
++ GB_OPERATION_FLAG_SHORT_RESPONSE,
++ NULL, 0,
++ (void *)capabilities, size);
++ if (ret)
++ gcam_err(gcam, "failed to retrieve capabilities: %d\n", ret);
++
++done:
++ mutex_unlock(&gcam->mutex);
++
++ gb_pm_runtime_put_autosuspend(gcam->bundle);
++
++ return ret;
++}
++
++static int gb_camera_configure_streams(struct gb_camera *gcam,
++ unsigned int *num_streams,
++ unsigned int *flags,
++ struct gb_camera_stream_config *streams,
++ struct gb_camera_csi_params *csi_params)
++{
++ struct gb_camera_configure_streams_request *req;
++ struct gb_camera_configure_streams_response *resp;
++ unsigned int nstreams = *num_streams;
++ unsigned int i;
++ size_t req_size;
++ size_t resp_size;
++ int ret;
++
++ if (nstreams > GB_CAMERA_MAX_STREAMS)
++ return -EINVAL;
++
++ req_size = sizeof(*req) + nstreams * sizeof(req->config[0]);
++ resp_size = sizeof(*resp) + nstreams * sizeof(resp->config[0]);
++
++ req = kmalloc(req_size, GFP_KERNEL);
++ resp = kmalloc(resp_size, GFP_KERNEL);
++ if (!req || !resp) {
++ kfree(req);
++ kfree(resp);
++ return -ENOMEM;
++ }
++
++ req->num_streams = nstreams;
++ req->flags = *flags;
++ req->padding = 0;
++
++ for (i = 0; i < nstreams; ++i) {
++ struct gb_camera_stream_config_request *cfg = &req->config[i];
++
++ cfg->width = cpu_to_le16(streams[i].width);
++ cfg->height = cpu_to_le16(streams[i].height);
++ cfg->format = cpu_to_le16(streams[i].format);
++ cfg->padding = 0;
++ }
++
++ mutex_lock(&gcam->mutex);
++
++ ret = gb_pm_runtime_get_sync(gcam->bundle);
++ if (ret)
++ goto done_skip_pm_put;
++
++ if (!gcam->connection) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = gb_camera_operation_sync_flags(gcam->connection,
++ GB_CAMERA_TYPE_CONFIGURE_STREAMS,
++ GB_OPERATION_FLAG_SHORT_RESPONSE,
++ req, req_size,
++ resp, &resp_size);
++ if (ret < 0)
++ goto done;
++
++ ret = gb_camera_configure_streams_validate_response(gcam, resp,
++ nstreams);
++ if (ret < 0)
++ goto done;
++
++ *flags = resp->flags;
++ *num_streams = resp->num_streams;
++
++ for (i = 0; i < resp->num_streams; ++i) {
++ struct gb_camera_stream_config_response *cfg = &resp->config[i];
++
++ streams[i].width = le16_to_cpu(cfg->width);
++ streams[i].height = le16_to_cpu(cfg->height);
++ streams[i].format = le16_to_cpu(cfg->format);
++ streams[i].vc = cfg->virtual_channel;
++ streams[i].dt[0] = cfg->data_type[0];
++ streams[i].dt[1] = cfg->data_type[1];
++ streams[i].max_size = le32_to_cpu(cfg->max_size);
++ }
++
++ if ((resp->flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED) ||
++ (req->flags & GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY))
++ goto done;
++
++ if (gcam->state == GB_CAMERA_STATE_CONFIGURED) {
++ gb_camera_teardown_data_connection(gcam);
++ gcam->state = GB_CAMERA_STATE_UNCONFIGURED;
++
++ /*
++ * When unconfiguring streams release the PM runtime reference
++ * that was acquired when streams were configured. The bundle
++ * won't be suspended until the PM runtime reference acquired at
++ * the beginning of this function gets released right before
++ * returning.
++ */
++ gb_pm_runtime_put_noidle(gcam->bundle);
++ }
++
++ if (resp->num_streams == 0)
++ goto done;
++
++ /*
++ * Make sure the bundle won't be suspended until streams get
++ * unconfigured after the stream is configured successfully
++ */
++ gb_pm_runtime_get_noresume(gcam->bundle);
++
++ /* Setup CSI-2 connection from APB-A to AP */
++ ret = gb_camera_setup_data_connection(gcam, resp, csi_params);
++ if (ret < 0) {
++ memset(req, 0, sizeof(*req));
++ gb_operation_sync(gcam->connection,
++ GB_CAMERA_TYPE_CONFIGURE_STREAMS,
++ req, sizeof(*req),
++ resp, sizeof(*resp));
++ *flags = 0;
++ *num_streams = 0;
++ gb_pm_runtime_put_noidle(gcam->bundle);
++ goto done;
++ }
++
++ gcam->state = GB_CAMERA_STATE_CONFIGURED;
++
++done:
++ gb_pm_runtime_put_autosuspend(gcam->bundle);
++
++done_skip_pm_put:
++ mutex_unlock(&gcam->mutex);
++ kfree(req);
++ kfree(resp);
++ return ret;
++}
++
++static int gb_camera_capture(struct gb_camera *gcam, u32 request_id,
++ unsigned int streams, unsigned int num_frames,
++ size_t settings_size, const void *settings)
++{
++ struct gb_camera_capture_request *req;
++ size_t req_size;
++ int ret;
++
++ if (settings_size > GB_CAMERA_MAX_SETTINGS_SIZE)
++ return -EINVAL;
++
++ req_size = sizeof(*req) + settings_size;
++ req = kmalloc(req_size, GFP_KERNEL);
++ if (!req)
++ return -ENOMEM;
++
++ req->request_id = cpu_to_le32(request_id);
++ req->streams = streams;
++ req->padding = 0;
++ req->num_frames = cpu_to_le16(num_frames);
++ memcpy(req->settings, settings, settings_size);
++
++ mutex_lock(&gcam->mutex);
++
++ if (!gcam->connection) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_CAPTURE,
++ req, req_size, NULL, 0);
++done:
++ mutex_unlock(&gcam->mutex);
++
++ kfree(req);
++
++ return ret;
++}
++
++static int gb_camera_flush(struct gb_camera *gcam, u32 *request_id)
++{
++ struct gb_camera_flush_response resp;
++ int ret;
++
++ mutex_lock(&gcam->mutex);
++
++ if (!gcam->connection) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_FLUSH, NULL, 0,
++ &resp, sizeof(resp));
++
++ if (ret < 0)
++ goto done;
++
++ if (request_id)
++ *request_id = le32_to_cpu(resp.request_id);
++
++done:
++ mutex_unlock(&gcam->mutex);
++
++ return ret;
++}
++
++static int gb_camera_request_handler(struct gb_operation *op)
++{
++ struct gb_camera *gcam = gb_connection_get_data(op->connection);
++ struct gb_camera_metadata_request *payload;
++ struct gb_message *request;
++
++ if (op->type != GB_CAMERA_TYPE_METADATA) {
++ gcam_err(gcam, "Unsupported unsolicited event: %u\n", op->type);
++ return -EINVAL;
++ }
++
++ request = op->request;
++
++ if (request->payload_size < sizeof(*payload)) {
++ gcam_err(gcam, "Wrong event size received (%zu < %zu)\n",
++ request->payload_size, sizeof(*payload));
++ return -EINVAL;
++ }
++
++ payload = request->payload;
++
++ gcam_dbg(gcam, "received metadata for request %u, frame %u, stream %u\n",
++ payload->request_id, payload->frame_number, payload->stream);
++
++ return 0;
++}
++
++/* -----------------------------------------------------------------------------
++ * Interface with HOST gmp camera.
++ */
++static unsigned int gb_camera_mbus_to_gb(enum v4l2_mbus_pixelcode mbus_code)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) {
++ if (gb_fmt_info[i].mbus_code == mbus_code)
++ return gb_fmt_info[i].gb_format;
++ }
++ return gb_fmt_info[0].gb_format;
++}
++
++static enum v4l2_mbus_pixelcode gb_camera_gb_to_mbus(u16 gb_fmt)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) {
++ if (gb_fmt_info[i].gb_format == gb_fmt)
++ return gb_fmt_info[i].mbus_code;
++ }
++ return gb_fmt_info[0].mbus_code;
++}
++
++static ssize_t gb_camera_op_capabilities(void *priv, char *data, size_t len)
++{
++ struct gb_camera *gcam = priv;
++ size_t capabilities_len = len;
++ int ret;
++
++ ret = gb_camera_capabilities(gcam, data, &capabilities_len);
++ if (ret)
++ return ret;
++
++ return capabilities_len;
++}
++
++static int gb_camera_op_configure_streams(void *priv, unsigned int *nstreams,
++ unsigned int *flags, struct gb_camera_stream *streams,
++ struct gb_camera_csi_params *csi_params)
++{
++ struct gb_camera *gcam = priv;
++ struct gb_camera_stream_config *gb_streams;
++ unsigned int gb_flags = 0;
++ unsigned int gb_nstreams = *nstreams;
++ unsigned int i;
++ int ret;
++
++ if (gb_nstreams > GB_CAMERA_MAX_STREAMS)
++ return -EINVAL;
++
++ gb_streams = kzalloc(gb_nstreams * sizeof(*gb_streams), GFP_KERNEL);
++ if (!gb_streams)
++ return -ENOMEM;
++
++ for (i = 0; i < gb_nstreams; i++) {
++ gb_streams[i].width = streams[i].width;
++ gb_streams[i].height = streams[i].height;
++ gb_streams[i].format =
++ gb_camera_mbus_to_gb(streams[i].pixel_code);
++ }
++
++ if (*flags & GB_CAMERA_IN_FLAG_TEST)
++ gb_flags |= GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY;
++
++ ret = gb_camera_configure_streams(gcam, &gb_nstreams,
++ &gb_flags, gb_streams, csi_params);
++ if (ret < 0)
++ goto done;
++ if (gb_nstreams > *nstreams) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ *flags = 0;
++ if (gb_flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED)
++ *flags |= GB_CAMERA_OUT_FLAG_ADJUSTED;
++
++ for (i = 0; i < gb_nstreams; i++) {
++ streams[i].width = gb_streams[i].width;
++ streams[i].height = gb_streams[i].height;
++ streams[i].vc = gb_streams[i].vc;
++ streams[i].dt[0] = gb_streams[i].dt[0];
++ streams[i].dt[1] = gb_streams[i].dt[1];
++ streams[i].max_size = gb_streams[i].max_size;
++ streams[i].pixel_code =
++ gb_camera_gb_to_mbus(gb_streams[i].format);
++ }
++ *nstreams = gb_nstreams;
++
++done:
++ kfree(gb_streams);
++ return ret;
++}
++
++static int gb_camera_op_capture(void *priv, u32 request_id,
++ unsigned int streams, unsigned int num_frames,
++ size_t settings_size, const void *settings)
++{
++ struct gb_camera *gcam = priv;
++
++ return gb_camera_capture(gcam, request_id, streams, num_frames,
++ settings_size, settings);
++}
++
++static int gb_camera_op_flush(void *priv, u32 *request_id)
++{
++ struct gb_camera *gcam = priv;
++
++ return gb_camera_flush(gcam, request_id);
++}
++
++static const struct gb_camera_ops gb_cam_ops = {
++ .capabilities = gb_camera_op_capabilities,
++ .configure_streams = gb_camera_op_configure_streams,
++ .capture = gb_camera_op_capture,
++ .flush = gb_camera_op_flush,
++};
++
++/* -----------------------------------------------------------------------------
++ * DebugFS
++ */
++
++static ssize_t gb_camera_debugfs_capabilities(struct gb_camera *gcam,
++ char *buf, size_t len)
++{
++ struct gb_camera_debugfs_buffer *buffer =
++ &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES];
++ size_t size = 1024;
++ unsigned int i;
++ u8 *caps;
++ int ret;
++
++ caps = kmalloc(size, GFP_KERNEL);
++ if (!caps)
++ return -ENOMEM;
++
++ ret = gb_camera_capabilities(gcam, caps, &size);
++ if (ret < 0)
++ goto done;
++
++ /*
++ * hex_dump_to_buffer() doesn't return the number of bytes dumped prior
++ * to v4.0, we need our own implementation :-(
++ */
++ buffer->length = 0;
++
++ for (i = 0; i < size; i += 16) {
++ unsigned int nbytes = min_t(unsigned int, size - i, 16);
++
++ buffer->length += sprintf(buffer->data + buffer->length,
++ "%*ph\n", nbytes, caps + i);
++ }
++
++done:
++ kfree(caps);
++ return ret;
++}
++
++static ssize_t gb_camera_debugfs_configure_streams(struct gb_camera *gcam,
++ char *buf, size_t len)
++{
++ struct gb_camera_debugfs_buffer *buffer =
++ &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_STREAMS];
++ struct gb_camera_stream_config *streams;
++ unsigned int nstreams;
++ unsigned int flags;
++ unsigned int i;
++ char *token;
++ int ret;
++
++ /* Retrieve number of streams to configure */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ return -EINVAL;
++
++ ret = kstrtouint(token, 10, &nstreams);
++ if (ret < 0)
++ return ret;
++
++ if (nstreams > GB_CAMERA_MAX_STREAMS)
++ return -EINVAL;
++
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ return -EINVAL;
++
++ ret = kstrtouint(token, 10, &flags);
++ if (ret < 0)
++ return ret;
++
++ /* For each stream to configure parse width, height and format */
++ streams = kzalloc(nstreams * sizeof(*streams), GFP_KERNEL);
++ if (!streams)
++ return -ENOMEM;
++
++ for (i = 0; i < nstreams; ++i) {
++ struct gb_camera_stream_config *stream = &streams[i];
++
++ /* width */
++ token = strsep(&buf, ";");
++ if (token == NULL) {
++ ret = -EINVAL;
++ goto done;
++ }
++ ret = kstrtouint(token, 10, &stream->width);
++ if (ret < 0)
++ goto done;
++
++ /* height */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ goto done;
++
++ ret = kstrtouint(token, 10, &stream->height);
++ if (ret < 0)
++ goto done;
++
++ /* Image format code */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ goto done;
++
++ ret = kstrtouint(token, 16, &stream->format);
++ if (ret < 0)
++ goto done;
++ }
++
++ ret = gb_camera_configure_streams(gcam, &nstreams, &flags, streams,
++ NULL);
++ if (ret < 0)
++ goto done;
++
++ buffer->length = sprintf(buffer->data, "%u;%u;", nstreams, flags);
++
++ for (i = 0; i < nstreams; ++i) {
++ struct gb_camera_stream_config *stream = &streams[i];
++
++ buffer->length += sprintf(buffer->data + buffer->length,
++ "%u;%u;%u;%u;%u;%u;%u;",
++ stream->width, stream->height,
++ stream->format, stream->vc,
++ stream->dt[0], stream->dt[1],
++ stream->max_size);
++ }
++
++ ret = len;
++
++done:
++ kfree(streams);
++ return ret;
++};
++
++static ssize_t gb_camera_debugfs_capture(struct gb_camera *gcam,
++ char *buf, size_t len)
++{
++ unsigned int request_id;
++ unsigned int streams_mask;
++ unsigned int num_frames;
++ char *token;
++ int ret;
++
++ /* Request id */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ return -EINVAL;
++ ret = kstrtouint(token, 10, &request_id);
++ if (ret < 0)
++ return ret;
++
++ /* Stream mask */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ return -EINVAL;
++ ret = kstrtouint(token, 16, &streams_mask);
++ if (ret < 0)
++ return ret;
++
++ /* number of frames */
++ token = strsep(&buf, ";");
++ if (token == NULL)
++ return -EINVAL;
++ ret = kstrtouint(token, 10, &num_frames);
++ if (ret < 0)
++ return ret;
++
++ ret = gb_camera_capture(gcam, request_id, streams_mask, num_frames, 0,
++ NULL);
++ if (ret < 0)
++ return ret;
++
++ return len;
++}
++
++static ssize_t gb_camera_debugfs_flush(struct gb_camera *gcam,
++ char *buf, size_t len)
++{
++ struct gb_camera_debugfs_buffer *buffer =
++ &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_FLUSH];
++ unsigned int req_id;
++ int ret;
++
++ ret = gb_camera_flush(gcam, &req_id);
++ if (ret < 0)
++ return ret;
++
++ buffer->length = sprintf(buffer->data, "%u", req_id);
++
++ return len;
++}
++
++struct gb_camera_debugfs_entry {
++ const char *name;
++ unsigned int mask;
++ unsigned int buffer;
++ ssize_t (*execute)(struct gb_camera *gcam, char *buf, size_t len);
++};
++
++static const struct gb_camera_debugfs_entry gb_camera_debugfs_entries[] = {
++ {
++ .name = "capabilities",
++ .mask = S_IFREG | S_IRUGO,
++ .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES,
++ .execute = gb_camera_debugfs_capabilities,
++ }, {
++ .name = "configure_streams",
++ .mask = S_IFREG | S_IRUGO | S_IWUGO,
++ .buffer = GB_CAMERA_DEBUGFS_BUFFER_STREAMS,
++ .execute = gb_camera_debugfs_configure_streams,
++ }, {
++ .name = "capture",
++ .mask = S_IFREG | S_IRUGO | S_IWUGO,
++ .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPTURE,
++ .execute = gb_camera_debugfs_capture,
++ }, {
++ .name = "flush",
++ .mask = S_IFREG | S_IRUGO | S_IWUGO,
++ .buffer = GB_CAMERA_DEBUGFS_BUFFER_FLUSH,
++ .execute = gb_camera_debugfs_flush,
++ },
++};
++
++static ssize_t gb_camera_debugfs_read(struct file *file, char __user *buf,
++ size_t len, loff_t *offset)
++{
++ const struct gb_camera_debugfs_entry *op = file->private_data;
++ struct gb_camera *gcam = file->f_inode->i_private;
++ struct gb_camera_debugfs_buffer *buffer;
++ ssize_t ret;
++
++ /* For read-only entries the operation is triggered by a read. */
++ if (!(op->mask & S_IWUGO)) {
++ ret = op->execute(gcam, NULL, 0);
++ if (ret < 0)
++ return ret;
++ }
++
++ buffer = &gcam->debugfs.buffers[op->buffer];
++
++ return simple_read_from_buffer(buf, len, offset, buffer->data,
++ buffer->length);
++}
++
++static ssize_t gb_camera_debugfs_write(struct file *file,
++ const char __user *buf, size_t len,
++ loff_t *offset)
++{
++ const struct gb_camera_debugfs_entry *op = file->private_data;
++ struct gb_camera *gcam = file->f_inode->i_private;
++ ssize_t ret;
++ char *kbuf;
++
++ if (len > 1024)
++ return -EINVAL;
++
++ kbuf = kmalloc(len + 1, GFP_KERNEL);
++ if (kbuf == NULL)
++ return -ENOMEM;
++
++ if (copy_from_user(kbuf, buf, len)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ kbuf[len] = '\0';
++
++ ret = op->execute(gcam, kbuf, len);
++
++done:
++ kfree(kbuf);
++ return ret;
++}
++
++static int gb_camera_debugfs_open(struct inode *inode, struct file *file)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) {
++ const struct gb_camera_debugfs_entry *entry =
++ &gb_camera_debugfs_entries[i];
++
++ if (!strcmp(file->f_path.dentry->d_iname, entry->name)) {
++ file->private_data = (void *)entry;
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static const struct file_operations gb_camera_debugfs_ops = {
++ .open = gb_camera_debugfs_open,
++ .read = gb_camera_debugfs_read,
++ .write = gb_camera_debugfs_write,
++};
++
++static int gb_camera_debugfs_init(struct gb_camera *gcam)
++{
++ struct gb_connection *connection = gcam->connection;
++ char dirname[27];
++ unsigned int i;
++
++ /*
++ * Create root debugfs entry and a file entry for each camera operation.
++ */
++ snprintf(dirname, 27, "camera-%u.%u", connection->intf->interface_id,
++ gcam->bundle->id);
++
++ gcam->debugfs.root = debugfs_create_dir(dirname, gb_debugfs_get());
++ if (IS_ERR(gcam->debugfs.root)) {
++ gcam_err(gcam, "debugfs root create failed (%ld)\n",
++ PTR_ERR(gcam->debugfs.root));
++ return PTR_ERR(gcam->debugfs.root);
++ }
++
++ gcam->debugfs.buffers = vmalloc(sizeof(*gcam->debugfs.buffers) *
++ GB_CAMERA_DEBUGFS_BUFFER_MAX);
++ if (!gcam->debugfs.buffers)
++ return -ENOMEM;
++
++ for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) {
++ const struct gb_camera_debugfs_entry *entry =
++ &gb_camera_debugfs_entries[i];
++ struct dentry *dentry;
++
++ gcam->debugfs.buffers[i].length = 0;
++
++ dentry = debugfs_create_file(entry->name, entry->mask,
++ gcam->debugfs.root, gcam,
++ &gb_camera_debugfs_ops);
++ if (IS_ERR(dentry)) {
++ gcam_err(gcam,
++ "debugfs operation %s create failed (%ld)\n",
++ entry->name, PTR_ERR(dentry));
++ return PTR_ERR(dentry);
++ }
++ }
++
++ return 0;
++}
++
++static void gb_camera_debugfs_cleanup(struct gb_camera *gcam)
++{
++ debugfs_remove_recursive(gcam->debugfs.root);
++
++ vfree(gcam->debugfs.buffers);
++}
++
++/* -----------------------------------------------------------------------------
++ * Init & Cleanup
++ */
++
++static void gb_camera_cleanup(struct gb_camera *gcam)
++{
++ gb_camera_debugfs_cleanup(gcam);
++
++ mutex_lock(&gcam->mutex);
++ if (gcam->data_connection) {
++ gb_connection_disable(gcam->data_connection);
++ gb_connection_destroy(gcam->data_connection);
++ gcam->data_connection = NULL;
++ }
++
++ if (gcam->connection) {
++ gb_connection_disable(gcam->connection);
++ gb_connection_destroy(gcam->connection);
++ gcam->connection = NULL;
++ }
++ mutex_unlock(&gcam->mutex);
++}
++
++static void gb_camera_release_module(struct kref *ref)
++{
++ struct gb_camera_module *cam_mod =
++ container_of(ref, struct gb_camera_module, refcount);
++ kfree(cam_mod->priv);
++}
++
++static int gb_camera_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct gb_connection *conn;
++ struct gb_camera *gcam;
++ u16 mgmt_cport_id = 0;
++ u16 data_cport_id = 0;
++ unsigned int i;
++ int ret;
++
++ /*
++ * The camera bundle must contain exactly two CPorts, one for the
++ * camera management protocol and one for the camera data protocol.
++ */
++ if (bundle->num_cports != 2)
++ return -ENODEV;
++
++ for (i = 0; i < bundle->num_cports; ++i) {
++ struct greybus_descriptor_cport *desc = &bundle->cport_desc[i];
++
++ switch (desc->protocol_id) {
++ case GREYBUS_PROTOCOL_CAMERA_MGMT:
++ mgmt_cport_id = le16_to_cpu(desc->id);
++ break;
++ case GREYBUS_PROTOCOL_CAMERA_DATA:
++ data_cport_id = le16_to_cpu(desc->id);
++ break;
++ default:
++ return -ENODEV;
++ }
++ }
++
++ if (!mgmt_cport_id || !data_cport_id)
++ return -ENODEV;
++
++ gcam = kzalloc(sizeof(*gcam), GFP_KERNEL);
++ if (!gcam)
++ return -ENOMEM;
++
++ mutex_init(&gcam->mutex);
++
++ gcam->bundle = bundle;
++ gcam->state = GB_CAMERA_STATE_UNCONFIGURED;
++ gcam->data_cport_id = data_cport_id;
++
++ conn = gb_connection_create(bundle, mgmt_cport_id,
++ gb_camera_request_handler);
++ if (IS_ERR(conn)) {
++ ret = PTR_ERR(conn);
++ goto error;
++ }
++
++ gcam->connection = conn;
++ gb_connection_set_data(conn, gcam);
++
++ ret = gb_connection_enable(conn);
++ if (ret)
++ goto error;
++
++ ret = gb_camera_debugfs_init(gcam);
++ if (ret < 0)
++ goto error;
++
++ gcam->module.priv = gcam;
++ gcam->module.ops = &gb_cam_ops;
++ gcam->module.interface_id = gcam->connection->intf->interface_id;
++ gcam->module.release = gb_camera_release_module;
++ ret = gb_camera_register(&gcam->module);
++ if (ret < 0)
++ goto error;
++
++ greybus_set_drvdata(bundle, gcam);
++
++ gb_pm_runtime_put_autosuspend(gcam->bundle);
++
++ return 0;
++
++error:
++ gb_camera_cleanup(gcam);
++ kfree(gcam);
++ return ret;
++}
++
++static void gb_camera_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_camera *gcam = greybus_get_drvdata(bundle);
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ gb_pm_runtime_get_noresume(bundle);
++
++ gb_camera_cleanup(gcam);
++ gb_camera_unregister(&gcam->module);
++}
++
++static const struct greybus_bundle_id gb_camera_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
++ { },
++};
++
++#ifdef CONFIG_PM
++static int gb_camera_suspend(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ struct gb_camera *gcam = greybus_get_drvdata(bundle);
++
++ if (gcam->data_connection)
++ gb_connection_disable(gcam->data_connection);
++
++ gb_connection_disable(gcam->connection);
++
++ return 0;
++}
++
++static int gb_camera_resume(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ struct gb_camera *gcam = greybus_get_drvdata(bundle);
++ int ret;
++
++ ret = gb_connection_enable(gcam->connection);
++ if (ret) {
++ gcam_err(gcam, "failed to enable connection: %d\n", ret);
++ return ret;
++ }
++
++ if (gcam->data_connection) {
++ ret = gb_connection_enable(gcam->data_connection);
++ if (ret) {
++ gcam_err(gcam,
++ "failed to enable data connection: %d\n", ret);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops gb_camera_pm_ops = {
++ SET_RUNTIME_PM_OPS(gb_camera_suspend, gb_camera_resume, NULL)
++};
++
++static struct greybus_driver gb_camera_driver = {
++ .name = "camera",
++ .probe = gb_camera_probe,
++ .disconnect = gb_camera_disconnect,
++ .id_table = gb_camera_id_table,
++ .driver.pm = &gb_camera_pm_ops,
++};
++
++module_greybus_driver(gb_camera_driver);
++
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/greybus/gb-camera.h
+@@ -0,0 +1,127 @@
++/*
++ * Greybus Camera protocol driver.
++ *
++ * Copyright 2015 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++#ifndef __GB_CAMERA_H
++#define __GB_CAMERA_H
++
++#include <linux/v4l2-mediabus.h>
++
++/* Input flags need to be set from the caller */
++#define GB_CAMERA_IN_FLAG_TEST (1 << 0)
++/* Output flags returned */
++#define GB_CAMERA_OUT_FLAG_ADJUSTED (1 << 0)
++
++/**
++ * struct gb_camera_stream - Represents greybus camera stream.
++ * @width: Stream width in pixels.
++ * @height: Stream height in pixels.
++ * @pixel_code: Media bus pixel code.
++ * @vc: MIPI CSI virtual channel.
++ * @dt: MIPI CSI data types. Most formats use a single data type, in which case
++ * the second element will be ignored.
++ * @max_size: Maximum size of a frame in bytes. The camera module guarantees
++ * that all data between the Frame Start and Frame End packet for
++ * the associated virtual channel and data type(s) will not exceed
++ * this size.
++ */
++struct gb_camera_stream {
++ unsigned int width;
++ unsigned int height;
++ enum v4l2_mbus_pixelcode pixel_code;
++ unsigned int vc;
++ unsigned int dt[2];
++ unsigned int max_size;
++};
++
++/**
++ * struct gb_camera_csi_params - CSI configuration parameters
++ * @num_lanes: number of CSI data lanes
++ * @clk_freq: CSI clock frequency in Hz
++ */
++struct gb_camera_csi_params {
++ unsigned int num_lanes;
++ unsigned int clk_freq;
++};
++
++/**
++ * struct gb_camera_ops - Greybus camera operations, used by the Greybus camera
++ * driver to expose operations to the host camera driver.
++ * @capabilities: Retrieve camera capabilities and store them in the buffer
++ * 'buf' capabilities. The buffer maximum size is specified by
++ * the caller in the 'size' parameter, and the effective
++ * capabilities size is returned from the function. If the buffer
++ * size is too small to hold the capabilities an error is
++ * returned and the buffer is left untouched.
++ *
++ * @configure_streams: Negotiate configuration and prepare the module for video
++ * capture. The caller specifies the number of streams it
++ * requests in the 'nstreams' argument and the associated
++ * streams configurations in the 'streams' argument. The
++ * GB_CAMERA_IN_FLAG_TEST 'flag' can be set to test a
++ * configuration without applying it, otherwise the
++ * configuration is applied by the module. The module can
++ * decide to modify the requested configuration, including
++ * using a different number of streams. In that case the
++ * modified configuration won't be applied, the
++ * GB_CAMERA_OUT_FLAG_ADJUSTED 'flag' will be set upon
++ * return, and the modified configuration and number of
++ * streams stored in 'streams' and 'array'. The module
++ * returns its CSI-2 bus parameters in the 'csi_params'
++ * structure in all cases.
++ *
++ * @capture: Submit a capture request. The supplied 'request_id' must be unique
++ * and higher than the IDs of all the previously submitted requests.
++ * The 'streams' argument specifies which streams are affected by the
++ * request in the form of a bitmask, with bits corresponding to the
++ * configured streams indexes. If the request contains settings, the
++ * 'settings' argument points to the settings buffer and its size is
++ * specified by the 'settings_size' argument. Otherwise the 'settings'
++ * argument should be set to NULL and 'settings_size' to 0.
++ *
++ * @flush: Flush the capture requests queue. Return the ID of the last request
++ * that will processed by the device before it stops transmitting video
++ * frames. All queued capture requests with IDs higher than the returned
++ * ID will be dropped without being processed.
++ */
++struct gb_camera_ops {
++ ssize_t (*capabilities)(void *priv, char *buf, size_t len);
++ int (*configure_streams)(void *priv, unsigned int *nstreams,
++ unsigned int *flags, struct gb_camera_stream *streams,
++ struct gb_camera_csi_params *csi_params);
++ int (*capture)(void *priv, u32 request_id,
++ unsigned int streams, unsigned int num_frames,
++ size_t settings_size, const void *settings);
++ int (*flush)(void *priv, u32 *request_id);
++};
++
++/**
++ * struct gb_camera_module - Represents greybus camera module.
++ * @priv: Module private data, passed to all camera operations.
++ * @ops: Greybus camera operation callbacks.
++ * @interface_id: Interface id of the module.
++ * @refcount: Reference counting object.
++ * @release: Module release function.
++ * @list: List entry in the camera modules list.
++ */
++struct gb_camera_module {
++ void *priv;
++ const struct gb_camera_ops *ops;
++
++ unsigned int interface_id;
++ struct kref refcount;
++ void (*release)(struct kref *kref);
++ struct list_head list; /* Global list */
++};
++
++#define gb_camera_call(f, op, args...) \
++ (!(f) ? -ENODEV : (((f)->ops->op) ? \
++ (f)->ops->op((f)->priv, ##args) : -ENOIOCTLCMD))
++
++int gb_camera_register(struct gb_camera_module *module);
++int gb_camera_unregister(struct gb_camera_module *module);
++
++#endif /* __GB_CAMERA_H */
diff --git a/greybus_core.patch b/greybus_core.patch
new file mode 100644
index 00000000000000..84ecc0b4c25779
--- /dev/null
+++ b/greybus_core.patch
@@ -0,0 +1,4431 @@
+
+---
+ drivers/greybus/arpc.h | 109 +++
+ drivers/greybus/authentication.c | 429 ++++++++++++++
+ drivers/greybus/bundle.c | 253 ++++++++
+ drivers/greybus/bundle.h | 90 ++
+ drivers/greybus/connection.c | 938 +++++++++++++++++++++++++++++++
+ drivers/greybus/connection.h | 129 ++++
+ drivers/greybus/control.c | 635 ++++++++++++++++++++
+ drivers/greybus/control.h | 65 ++
+ drivers/greybus/core.c | 361 +++++++++++
+ drivers/greybus/debugfs.c | 31 +
+ drivers/greybus/devices | 11
+ drivers/greybus/greybus.h | 154 +++++
+ drivers/greybus/greybus_authentication.h | 120 +++
+ drivers/greybus/greybus_id.h | 26
+ drivers/greybus/greybus_manifest.h | 177 +++++
+ drivers/greybus/manifest.c | 535 +++++++++++++++++
+ drivers/greybus/manifest.h | 16
+ drivers/greybus/module.c | 238 +++++++
+ drivers/greybus/module.h | 34 +
+ 19 files changed, 4351 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/arpc.h
+@@ -0,0 +1,109 @@
++/*
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __ARPC_H
++#define __ARPC_H
++
++/* APBridgeA RPC (ARPC) */
++
++enum arpc_result {
++ ARPC_SUCCESS = 0x00,
++ ARPC_NO_MEMORY = 0x01,
++ ARPC_INVALID = 0x02,
++ ARPC_TIMEOUT = 0x03,
++ ARPC_UNKNOWN_ERROR = 0xff,
++};
++
++struct arpc_request_message {
++ __le16 id; /* RPC unique id */
++ __le16 size; /* Size in bytes of header + payload */
++ __u8 type; /* RPC type */
++ __u8 data[0]; /* ARPC data */
++} __packed;
++
++struct arpc_response_message {
++ __le16 id; /* RPC unique id */
++ __u8 result; /* Result of RPC */
++} __packed;
++
++
++/* ARPC requests */
++#define ARPC_TYPE_CPORT_CONNECTED 0x01
++#define ARPC_TYPE_CPORT_QUIESCE 0x02
++#define ARPC_TYPE_CPORT_CLEAR 0x03
++#define ARPC_TYPE_CPORT_FLUSH 0x04
++#define ARPC_TYPE_CPORT_SHUTDOWN 0x05
++
++struct arpc_cport_connected_req {
++ __le16 cport_id;
++} __packed;
++
++struct arpc_cport_quiesce_req {
++ __le16 cport_id;
++ __le16 peer_space;
++ __le16 timeout;
++} __packed;
++
++struct arpc_cport_clear_req {
++ __le16 cport_id;
++} __packed;
++
++struct arpc_cport_flush_req {
++ __le16 cport_id;
++} __packed;
++
++struct arpc_cport_shutdown_req {
++ __le16 cport_id;
++ __le16 timeout;
++ __u8 phase;
++} __packed;
++
++#endif /* __ARPC_H */
+--- /dev/null
++++ b/drivers/greybus/authentication.c
+@@ -0,0 +1,429 @@
++/*
++ * Greybus Component Authentication Protocol (CAP) Driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/ioctl.h>
++#include <linux/uaccess.h>
++
++#include "greybus_authentication.h"
++#include "firmware.h"
++#include "greybus.h"
++
++#define CAP_TIMEOUT_MS 1000
++
++/*
++ * Number of minor devices this driver supports.
++ * There will be exactly one required per Interface.
++ */
++#define NUM_MINORS U8_MAX
++
++struct gb_cap {
++ struct device *parent;
++ struct gb_connection *connection;
++ struct kref kref;
++ struct list_head node;
++ bool disabled; /* connection getting disabled */
++
++ struct mutex mutex;
++ struct cdev cdev;
++ struct device *class_device;
++ dev_t dev_num;
++};
++
++static struct class *cap_class;
++static dev_t cap_dev_num;
++static DEFINE_IDA(cap_minors_map);
++static LIST_HEAD(cap_list);
++static DEFINE_MUTEX(list_mutex);
++
++static void cap_kref_release(struct kref *kref)
++{
++ struct gb_cap *cap = container_of(kref, struct gb_cap, kref);
++
++ kfree(cap);
++}
++
++/*
++ * All users of cap take a reference (from within list_mutex lock), before
++ * they get a pointer to play with. And the structure will be freed only after
++ * the last user has put the reference to it.
++ */
++static void put_cap(struct gb_cap *cap)
++{
++ kref_put(&cap->kref, cap_kref_release);
++}
++
++/* Caller must call put_cap() after using struct gb_cap */
++static struct gb_cap *get_cap(struct cdev *cdev)
++{
++ struct gb_cap *cap;
++
++ mutex_lock(&list_mutex);
++
++ list_for_each_entry(cap, &cap_list, node) {
++ if (&cap->cdev == cdev) {
++ kref_get(&cap->kref);
++ goto unlock;
++ }
++ }
++
++ cap = NULL;
++
++unlock:
++ mutex_unlock(&list_mutex);
++
++ return cap;
++}
++
++static int cap_get_endpoint_uid(struct gb_cap *cap, u8 *euid)
++{
++ struct gb_connection *connection = cap->connection;
++ struct gb_cap_get_endpoint_uid_response response;
++ int ret;
++
++ ret = gb_operation_sync(connection, GB_CAP_TYPE_GET_ENDPOINT_UID, NULL,
++ 0, &response, sizeof(response));
++ if (ret) {
++ dev_err(cap->parent, "failed to get endpoint uid (%d)\n", ret);
++ return ret;
++ }
++
++ memcpy(euid, response.uid, sizeof(response.uid));
++
++ return 0;
++}
++
++static int cap_get_ims_certificate(struct gb_cap *cap, u32 class, u32 id,
++ u8 *certificate, u32 *size, u8 *result)
++{
++ struct gb_connection *connection = cap->connection;
++ struct gb_cap_get_ims_certificate_request *request;
++ struct gb_cap_get_ims_certificate_response *response;
++ size_t max_size = gb_operation_get_payload_size_max(connection);
++ struct gb_operation *op;
++ int ret;
++
++ op = gb_operation_create_flags(connection,
++ GB_CAP_TYPE_GET_IMS_CERTIFICATE,
++ sizeof(*request), max_size,
++ GB_OPERATION_FLAG_SHORT_RESPONSE,
++ GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ request = op->request->payload;
++ request->certificate_class = cpu_to_le32(class);
++ request->certificate_id = cpu_to_le32(id);
++
++ ret = gb_operation_request_send_sync(op);
++ if (ret) {
++ dev_err(cap->parent, "failed to get certificate (%d)\n", ret);
++ goto done;
++ }
++
++ response = op->response->payload;
++ *result = response->result_code;
++ *size = op->response->payload_size - sizeof(*response);
++ memcpy(certificate, response->certificate, *size);
++
++done:
++ gb_operation_put(op);
++ return ret;
++}
++
++static int cap_authenticate(struct gb_cap *cap, u32 auth_type, u8 *uid,
++ u8 *challenge, u8 *result, u8 *auth_response,
++ u32 *signature_size, u8 *signature)
++{
++ struct gb_connection *connection = cap->connection;
++ struct gb_cap_authenticate_request *request;
++ struct gb_cap_authenticate_response *response;
++ size_t max_size = gb_operation_get_payload_size_max(connection);
++ struct gb_operation *op;
++ int ret;
++
++ op = gb_operation_create_flags(connection, GB_CAP_TYPE_AUTHENTICATE,
++ sizeof(*request), max_size,
++ GB_OPERATION_FLAG_SHORT_RESPONSE,
++ GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ request = op->request->payload;
++ request->auth_type = cpu_to_le32(auth_type);
++ memcpy(request->uid, uid, sizeof(request->uid));
++ memcpy(request->challenge, challenge, sizeof(request->challenge));
++
++ ret = gb_operation_request_send_sync(op);
++ if (ret) {
++ dev_err(cap->parent, "failed to authenticate (%d)\n", ret);
++ goto done;
++ }
++
++ response = op->response->payload;
++ *result = response->result_code;
++ *signature_size = op->response->payload_size - sizeof(*response);
++ memcpy(auth_response, response->response, sizeof(response->response));
++ memcpy(signature, response->signature, *signature_size);
++
++done:
++ gb_operation_put(op);
++ return ret;
++}
++
++/* Char device fops */
++
++static int cap_open(struct inode *inode, struct file *file)
++{
++ struct gb_cap *cap = get_cap(inode->i_cdev);
++
++ /* cap structure can't get freed until file descriptor is closed */
++ if (cap) {
++ file->private_data = cap;
++ return 0;
++ }
++
++ return -ENODEV;
++}
++
++static int cap_release(struct inode *inode, struct file *file)
++{
++ struct gb_cap *cap = file->private_data;
++
++ put_cap(cap);
++ return 0;
++}
++
++static int cap_ioctl(struct gb_cap *cap, unsigned int cmd,
++ void __user *buf)
++{
++ struct cap_ioc_get_endpoint_uid endpoint_uid;
++ struct cap_ioc_get_ims_certificate *ims_cert;
++ struct cap_ioc_authenticate *authenticate;
++ size_t size;
++ int ret;
++
++ switch (cmd) {
++ case CAP_IOC_GET_ENDPOINT_UID:
++ ret = cap_get_endpoint_uid(cap, endpoint_uid.uid);
++ if (ret)
++ return ret;
++
++ if (copy_to_user(buf, &endpoint_uid, sizeof(endpoint_uid)))
++ return -EFAULT;
++
++ return 0;
++ case CAP_IOC_GET_IMS_CERTIFICATE:
++ size = sizeof(*ims_cert);
++ ims_cert = memdup_user(buf, size);
++ if (IS_ERR(ims_cert))
++ return PTR_ERR(ims_cert);
++
++ ret = cap_get_ims_certificate(cap, ims_cert->certificate_class,
++ ims_cert->certificate_id,
++ ims_cert->certificate,
++ &ims_cert->cert_size,
++ &ims_cert->result_code);
++ if (!ret && copy_to_user(buf, ims_cert, size))
++ ret = -EFAULT;
++ kfree(ims_cert);
++
++ return ret;
++ case CAP_IOC_AUTHENTICATE:
++ size = sizeof(*authenticate);
++ authenticate = memdup_user(buf, size);
++ if (IS_ERR(authenticate))
++ return PTR_ERR(authenticate);
++
++ ret = cap_authenticate(cap, authenticate->auth_type,
++ authenticate->uid,
++ authenticate->challenge,
++ &authenticate->result_code,
++ authenticate->response,
++ &authenticate->signature_size,
++ authenticate->signature);
++ if (!ret && copy_to_user(buf, authenticate, size))
++ ret = -EFAULT;
++ kfree(authenticate);
++
++ return ret;
++ default:
++ return -ENOTTY;
++ }
++}
++
++static long cap_ioctl_unlocked(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ struct gb_cap *cap = file->private_data;
++ struct gb_bundle *bundle = cap->connection->bundle;
++ int ret = -ENODEV;
++
++ /*
++ * Serialize ioctls.
++ *
++ * We don't want the user to do multiple authentication operations in
++ * parallel.
++ *
++ * This is also used to protect ->disabled, which is used to check if
++ * the connection is getting disconnected, so that we don't start any
++ * new operations.
++ */
++ mutex_lock(&cap->mutex);
++ if (!cap->disabled) {
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (!ret) {
++ ret = cap_ioctl(cap, cmd, (void __user *)arg);
++ gb_pm_runtime_put_autosuspend(bundle);
++ }
++ }
++ mutex_unlock(&cap->mutex);
++
++ return ret;
++}
++
++static const struct file_operations cap_fops = {
++ .owner = THIS_MODULE,
++ .open = cap_open,
++ .release = cap_release,
++ .unlocked_ioctl = cap_ioctl_unlocked,
++};
++
++int gb_cap_connection_init(struct gb_connection *connection)
++{
++ struct gb_cap *cap;
++ int ret, minor;
++
++ if (!connection)
++ return 0;
++
++ cap = kzalloc(sizeof(*cap), GFP_KERNEL);
++ if (!cap)
++ return -ENOMEM;
++
++ cap->parent = &connection->bundle->dev;
++ cap->connection = connection;
++ mutex_init(&cap->mutex);
++ gb_connection_set_data(connection, cap);
++ kref_init(&cap->kref);
++
++ mutex_lock(&list_mutex);
++ list_add(&cap->node, &cap_list);
++ mutex_unlock(&list_mutex);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto err_list_del;
++
++ minor = ida_simple_get(&cap_minors_map, 0, NUM_MINORS, GFP_KERNEL);
++ if (minor < 0) {
++ ret = minor;
++ goto err_connection_disable;
++ }
++
++ /* Add a char device to allow userspace to interact with cap */
++ cap->dev_num = MKDEV(MAJOR(cap_dev_num), minor);
++ cdev_init(&cap->cdev, &cap_fops);
++
++ ret = cdev_add(&cap->cdev, cap->dev_num, 1);
++ if (ret)
++ goto err_remove_ida;
++
++ /* Add a soft link to the previously added char-dev within the bundle */
++ cap->class_device = device_create(cap_class, cap->parent, cap->dev_num,
++ NULL, "gb-authenticate-%d", minor);
++ if (IS_ERR(cap->class_device)) {
++ ret = PTR_ERR(cap->class_device);
++ goto err_del_cdev;
++ }
++
++ return 0;
++
++err_del_cdev:
++ cdev_del(&cap->cdev);
++err_remove_ida:
++ ida_simple_remove(&cap_minors_map, minor);
++err_connection_disable:
++ gb_connection_disable(connection);
++err_list_del:
++ mutex_lock(&list_mutex);
++ list_del(&cap->node);
++ mutex_unlock(&list_mutex);
++
++ put_cap(cap);
++
++ return ret;
++}
++
++void gb_cap_connection_exit(struct gb_connection *connection)
++{
++ struct gb_cap *cap;
++
++ if (!connection)
++ return;
++
++ cap = gb_connection_get_data(connection);
++
++ device_destroy(cap_class, cap->dev_num);
++ cdev_del(&cap->cdev);
++ ida_simple_remove(&cap_minors_map, MINOR(cap->dev_num));
++
++ /*
++ * Disallow any new ioctl operations on the char device and wait for
++ * existing ones to finish.
++ */
++ mutex_lock(&cap->mutex);
++ cap->disabled = true;
++ mutex_unlock(&cap->mutex);
++
++ /* All pending greybus operations should have finished by now */
++ gb_connection_disable(cap->connection);
++
++ /* Disallow new users to get access to the cap structure */
++ mutex_lock(&list_mutex);
++ list_del(&cap->node);
++ mutex_unlock(&list_mutex);
++
++ /*
++ * All current users of cap would have taken a reference to it by
++ * now, we can drop our reference and wait the last user will get
++ * cap freed.
++ */
++ put_cap(cap);
++}
++
++int cap_init(void)
++{
++ int ret;
++
++ cap_class = class_create(THIS_MODULE, "gb_authenticate");
++ if (IS_ERR(cap_class))
++ return PTR_ERR(cap_class);
++
++ ret = alloc_chrdev_region(&cap_dev_num, 0, NUM_MINORS,
++ "gb_authenticate");
++ if (ret)
++ goto err_remove_class;
++
++ return 0;
++
++err_remove_class:
++ class_destroy(cap_class);
++ return ret;
++}
++
++void cap_exit(void)
++{
++ unregister_chrdev_region(cap_dev_num, NUM_MINORS);
++ class_destroy(cap_class);
++ ida_destroy(&cap_minors_map);
++}
+--- /dev/null
++++ b/drivers/greybus/bundle.c
+@@ -0,0 +1,253 @@
++/*
++ * Greybus bundles
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++static ssize_t bundle_class_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++
++ return sprintf(buf, "0x%02x\n", bundle->class);
++}
++static DEVICE_ATTR_RO(bundle_class);
++
++static ssize_t bundle_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++
++ return sprintf(buf, "%u\n", bundle->id);
++}
++static DEVICE_ATTR_RO(bundle_id);
++
++static ssize_t state_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++
++ if (bundle->state == NULL)
++ return sprintf(buf, "\n");
++
++ return sprintf(buf, "%s\n", bundle->state);
++}
++
++static ssize_t state_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++
++ kfree(bundle->state);
++ bundle->state = kstrdup(buf, GFP_KERNEL);
++ if (!bundle->state)
++ return -ENOMEM;
++
++ /* Tell userspace that the file contents changed */
++ sysfs_notify(&bundle->dev.kobj, NULL, "state");
++
++ return size;
++}
++static DEVICE_ATTR_RW(state);
++
++static struct attribute *bundle_attrs[] = {
++ &dev_attr_bundle_class.attr,
++ &dev_attr_bundle_id.attr,
++ &dev_attr_state.attr,
++ NULL,
++};
++
++ATTRIBUTE_GROUPS(bundle);
++
++static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
++ u8 bundle_id)
++{
++ struct gb_bundle *bundle;
++
++ list_for_each_entry(bundle, &intf->bundles, links) {
++ if (bundle->id == bundle_id)
++ return bundle;
++ }
++
++ return NULL;
++}
++
++static void gb_bundle_release(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++
++ trace_gb_bundle_release(bundle);
++
++ kfree(bundle->state);
++ kfree(bundle->cport_desc);
++ kfree(bundle);
++}
++
++#ifdef CONFIG_PM
++static void gb_bundle_disable_all_connections(struct gb_bundle *bundle)
++{
++ struct gb_connection *connection;
++
++ list_for_each_entry(connection, &bundle->connections, bundle_links)
++ gb_connection_disable(connection);
++}
++
++static void gb_bundle_enable_all_connections(struct gb_bundle *bundle)
++{
++ struct gb_connection *connection;
++
++ list_for_each_entry(connection, &bundle->connections, bundle_links)
++ gb_connection_enable(connection);
++}
++
++static int gb_bundle_suspend(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ const struct dev_pm_ops *pm = dev->driver->pm;
++ int ret;
++
++ if (pm && pm->runtime_suspend) {
++ ret = pm->runtime_suspend(&bundle->dev);
++ if (ret)
++ return ret;
++ } else {
++ gb_bundle_disable_all_connections(bundle);
++ }
++
++ ret = gb_control_bundle_suspend(bundle->intf->control, bundle->id);
++ if (ret) {
++ if (pm && pm->runtime_resume)
++ ret = pm->runtime_resume(dev);
++ else
++ gb_bundle_enable_all_connections(bundle);
++
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_bundle_resume(struct device *dev)
++{
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ const struct dev_pm_ops *pm = dev->driver->pm;
++ int ret;
++
++ ret = gb_control_bundle_resume(bundle->intf->control, bundle->id);
++ if (ret)
++ return ret;
++
++ if (pm && pm->runtime_resume) {
++ ret = pm->runtime_resume(dev);
++ if (ret)
++ return ret;
++ } else {
++ gb_bundle_enable_all_connections(bundle);
++ }
++
++ return 0;
++}
++
++static int gb_bundle_idle(struct device *dev)
++{
++ pm_runtime_mark_last_busy(dev);
++ pm_request_autosuspend(dev);
++
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops gb_bundle_pm_ops = {
++ SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle)
++};
++
++struct device_type greybus_bundle_type = {
++ .name = "greybus_bundle",
++ .release = gb_bundle_release,
++ .pm = &gb_bundle_pm_ops,
++};
++
++/*
++ * Create a gb_bundle structure to represent a discovered
++ * bundle. Returns a pointer to the new bundle or a null
++ * pointer if a failure occurs due to memory exhaustion.
++ */
++struct gb_bundle *gb_bundle_create(struct gb_interface *intf, u8 bundle_id,
++ u8 class)
++{
++ struct gb_bundle *bundle;
++
++ if (bundle_id == BUNDLE_ID_NONE) {
++ dev_err(&intf->dev, "can't use bundle id %u\n", bundle_id);
++ return NULL;
++ }
++
++ /*
++ * Reject any attempt to reuse a bundle id. We initialize
++ * these serially, so there's no need to worry about keeping
++ * the interface bundle list locked here.
++ */
++ if (gb_bundle_find(intf, bundle_id)) {
++ dev_err(&intf->dev, "duplicate bundle id %u\n", bundle_id);
++ return NULL;
++ }
++
++ bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
++ if (!bundle)
++ return NULL;
++
++ bundle->intf = intf;
++ bundle->id = bundle_id;
++ bundle->class = class;
++ INIT_LIST_HEAD(&bundle->connections);
++
++ bundle->dev.parent = &intf->dev;
++ bundle->dev.bus = &greybus_bus_type;
++ bundle->dev.type = &greybus_bundle_type;
++ bundle->dev.groups = bundle_groups;
++ bundle->dev.dma_mask = intf->dev.dma_mask;
++ device_initialize(&bundle->dev);
++ dev_set_name(&bundle->dev, "%s.%d", dev_name(&intf->dev), bundle_id);
++
++ list_add(&bundle->links, &intf->bundles);
++
++ trace_gb_bundle_create(bundle);
++
++ return bundle;
++}
++
++int gb_bundle_add(struct gb_bundle *bundle)
++{
++ int ret;
++
++ ret = device_add(&bundle->dev);
++ if (ret) {
++ dev_err(&bundle->dev, "failed to register bundle: %d\n", ret);
++ return ret;
++ }
++
++ trace_gb_bundle_add(bundle);
++
++ return 0;
++}
++
++/*
++ * Tear down a previously set up bundle.
++ */
++void gb_bundle_destroy(struct gb_bundle *bundle)
++{
++ trace_gb_bundle_destroy(bundle);
++
++ if (device_is_registered(&bundle->dev))
++ device_del(&bundle->dev);
++
++ list_del(&bundle->links);
++
++ put_device(&bundle->dev);
++}
+--- /dev/null
++++ b/drivers/greybus/bundle.h
+@@ -0,0 +1,90 @@
++/*
++ * Greybus bundles
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __BUNDLE_H
++#define __BUNDLE_H
++
++#include <linux/list.h>
++
++#define BUNDLE_ID_NONE U8_MAX
++
++/* Greybus "public" definitions" */
++struct gb_bundle {
++ struct device dev;
++ struct gb_interface *intf;
++
++ u8 id;
++ u8 class;
++ u8 class_major;
++ u8 class_minor;
++
++ size_t num_cports;
++ struct greybus_descriptor_cport *cport_desc;
++
++ struct list_head connections;
++ u8 *state;
++
++ struct list_head links; /* interface->bundles */
++};
++#define to_gb_bundle(d) container_of(d, struct gb_bundle, dev)
++
++/* Greybus "private" definitions" */
++struct gb_bundle *gb_bundle_create(struct gb_interface *intf, u8 bundle_id,
++ u8 class);
++int gb_bundle_add(struct gb_bundle *bundle);
++void gb_bundle_destroy(struct gb_bundle *bundle);
++
++/* Bundle Runtime PM wrappers */
++#ifdef CONFIG_PM
++static inline int gb_pm_runtime_get_sync(struct gb_bundle *bundle)
++{
++ int retval;
++
++ retval = pm_runtime_get_sync(&bundle->dev);
++ if (retval < 0) {
++ dev_err(&bundle->dev,
++ "pm_runtime_get_sync failed: %d\n", retval);
++ pm_runtime_put_noidle(&bundle->dev);
++ return retval;
++ }
++
++ return 0;
++}
++
++static inline int gb_pm_runtime_put_autosuspend(struct gb_bundle *bundle)
++{
++ int retval;
++
++ pm_runtime_mark_last_busy(&bundle->dev);
++ retval = pm_runtime_put_autosuspend(&bundle->dev);
++
++ return retval;
++}
++
++static inline void gb_pm_runtime_get_noresume(struct gb_bundle *bundle)
++{
++ pm_runtime_get_noresume(&bundle->dev);
++}
++
++static inline void gb_pm_runtime_put_noidle(struct gb_bundle *bundle)
++{
++ pm_runtime_put_noidle(&bundle->dev);
++}
++
++#else
++static inline int gb_pm_runtime_get_sync(struct gb_bundle *bundle)
++{ return 0; }
++static inline int gb_pm_runtime_put_autosuspend(struct gb_bundle *bundle)
++{ return 0; }
++
++static inline void gb_pm_runtime_get_noresume(struct gb_bundle *bundle) {}
++static inline void gb_pm_runtime_put_noidle(struct gb_bundle *bundle) {}
++#endif
++
++#endif /* __BUNDLE_H */
+--- /dev/null
++++ b/drivers/greybus/connection.c
+@@ -0,0 +1,938 @@
++/*
++ * Greybus connections
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/workqueue.h>
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++
++#define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT 1000
++
++
++static void gb_connection_kref_release(struct kref *kref);
++
++
++static DEFINE_SPINLOCK(gb_connections_lock);
++static DEFINE_MUTEX(gb_connection_mutex);
++
++
++/* Caller holds gb_connection_mutex. */
++static bool gb_connection_cport_in_use(struct gb_interface *intf, u16 cport_id)
++{
++ struct gb_host_device *hd = intf->hd;
++ struct gb_connection *connection;
++
++ list_for_each_entry(connection, &hd->connections, hd_links) {
++ if (connection->intf == intf &&
++ connection->intf_cport_id == cport_id)
++ return true;
++ }
++
++ return false;
++}
++
++static void gb_connection_get(struct gb_connection *connection)
++{
++ kref_get(&connection->kref);
++
++ trace_gb_connection_get(connection);
++}
++
++static void gb_connection_put(struct gb_connection *connection)
++{
++ trace_gb_connection_put(connection);
++
++ kref_put(&connection->kref, gb_connection_kref_release);
++}
++
++/*
++ * Returns a reference-counted pointer to the connection if found.
++ */
++static struct gb_connection *
++gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id)
++{
++ struct gb_connection *connection;
++ unsigned long flags;
++
++ spin_lock_irqsave(&gb_connections_lock, flags);
++ list_for_each_entry(connection, &hd->connections, hd_links)
++ if (connection->hd_cport_id == cport_id) {
++ gb_connection_get(connection);
++ goto found;
++ }
++ connection = NULL;
++found:
++ spin_unlock_irqrestore(&gb_connections_lock, flags);
++
++ return connection;
++}
++
++/*
++ * Callback from the host driver to let us know that data has been
++ * received on the bundle.
++ */
++void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
++ u8 *data, size_t length)
++{
++ struct gb_connection *connection;
++
++ trace_gb_hd_in(hd);
++
++ connection = gb_connection_hd_find(hd, cport_id);
++ if (!connection) {
++ dev_err(&hd->dev,
++ "nonexistent connection (%zu bytes dropped)\n", length);
++ return;
++ }
++ gb_connection_recv(connection, data, length);
++ gb_connection_put(connection);
++}
++EXPORT_SYMBOL_GPL(greybus_data_rcvd);
++
++static void gb_connection_kref_release(struct kref *kref)
++{
++ struct gb_connection *connection;
++
++ connection = container_of(kref, struct gb_connection, kref);
++
++ trace_gb_connection_release(connection);
++
++ kfree(connection);
++}
++
++static void gb_connection_init_name(struct gb_connection *connection)
++{
++ u16 hd_cport_id = connection->hd_cport_id;
++ u16 cport_id = 0;
++ u8 intf_id = 0;
++
++ if (connection->intf) {
++ intf_id = connection->intf->interface_id;
++ cport_id = connection->intf_cport_id;
++ }
++
++ snprintf(connection->name, sizeof(connection->name),
++ "%u/%u:%u", hd_cport_id, intf_id, cport_id);
++}
++
++/*
++ * _gb_connection_create() - create a Greybus connection
++ * @hd: host device of the connection
++ * @hd_cport_id: host-device cport id, or -1 for dynamic allocation
++ * @intf: remote interface, or NULL for static connections
++ * @bundle: remote-interface bundle (may be NULL)
++ * @cport_id: remote-interface cport id, or 0 for static connections
++ * @handler: request handler (may be NULL)
++ * @flags: connection flags
++ *
++ * Create a Greybus connection, representing the bidirectional link
++ * between a CPort on a (local) Greybus host device and a CPort on
++ * another Greybus interface.
++ *
++ * A connection also maintains the state of operations sent over the
++ * connection.
++ *
++ * Serialised against concurrent create and destroy using the
++ * gb_connection_mutex.
++ *
++ * Return: A pointer to the new connection if successful, or an ERR_PTR
++ * otherwise.
++ */
++static struct gb_connection *
++_gb_connection_create(struct gb_host_device *hd, int hd_cport_id,
++ struct gb_interface *intf,
++ struct gb_bundle *bundle, int cport_id,
++ gb_request_handler_t handler,
++ unsigned long flags)
++{
++ struct gb_connection *connection;
++ int ret;
++
++ mutex_lock(&gb_connection_mutex);
++
++ if (intf && gb_connection_cport_in_use(intf, cport_id)) {
++ dev_err(&intf->dev, "cport %u already in use\n", cport_id);
++ ret = -EBUSY;
++ goto err_unlock;
++ }
++
++ ret = gb_hd_cport_allocate(hd, hd_cport_id, flags);
++ if (ret < 0) {
++ dev_err(&hd->dev, "failed to allocate cport: %d\n", ret);
++ goto err_unlock;
++ }
++ hd_cport_id = ret;
++
++ connection = kzalloc(sizeof(*connection), GFP_KERNEL);
++ if (!connection) {
++ ret = -ENOMEM;
++ goto err_hd_cport_release;
++ }
++
++ connection->hd_cport_id = hd_cport_id;
++ connection->intf_cport_id = cport_id;
++ connection->hd = hd;
++ connection->intf = intf;
++ connection->bundle = bundle;
++ connection->handler = handler;
++ connection->flags = flags;
++ if (intf && (intf->quirks & GB_INTERFACE_QUIRK_NO_CPORT_FEATURES))
++ connection->flags |= GB_CONNECTION_FLAG_NO_FLOWCTRL;
++ connection->state = GB_CONNECTION_STATE_DISABLED;
++
++ atomic_set(&connection->op_cycle, 0);
++ mutex_init(&connection->mutex);
++ spin_lock_init(&connection->lock);
++ INIT_LIST_HEAD(&connection->operations);
++
++ connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1,
++ dev_name(&hd->dev), hd_cport_id);
++ if (!connection->wq) {
++ ret = -ENOMEM;
++ goto err_free_connection;
++ }
++
++ kref_init(&connection->kref);
++
++ gb_connection_init_name(connection);
++
++ spin_lock_irq(&gb_connections_lock);
++ list_add(&connection->hd_links, &hd->connections);
++
++ if (bundle)
++ list_add(&connection->bundle_links, &bundle->connections);
++ else
++ INIT_LIST_HEAD(&connection->bundle_links);
++
++ spin_unlock_irq(&gb_connections_lock);
++
++ mutex_unlock(&gb_connection_mutex);
++
++ trace_gb_connection_create(connection);
++
++ return connection;
++
++err_free_connection:
++ kfree(connection);
++err_hd_cport_release:
++ gb_hd_cport_release(hd, hd_cport_id);
++err_unlock:
++ mutex_unlock(&gb_connection_mutex);
++
++ return ERR_PTR(ret);
++}
++
++struct gb_connection *
++gb_connection_create_static(struct gb_host_device *hd, u16 hd_cport_id,
++ gb_request_handler_t handler)
++{
++ return _gb_connection_create(hd, hd_cport_id, NULL, NULL, 0, handler,
++ GB_CONNECTION_FLAG_HIGH_PRIO);
++}
++
++struct gb_connection *
++gb_connection_create_control(struct gb_interface *intf)
++{
++ return _gb_connection_create(intf->hd, -1, intf, NULL, 0, NULL,
++ GB_CONNECTION_FLAG_CONTROL |
++ GB_CONNECTION_FLAG_HIGH_PRIO);
++}
++
++struct gb_connection *
++gb_connection_create(struct gb_bundle *bundle, u16 cport_id,
++ gb_request_handler_t handler)
++{
++ struct gb_interface *intf = bundle->intf;
++
++ return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
++ handler, 0);
++}
++EXPORT_SYMBOL_GPL(gb_connection_create);
++
++struct gb_connection *
++gb_connection_create_flags(struct gb_bundle *bundle, u16 cport_id,
++ gb_request_handler_t handler,
++ unsigned long flags)
++{
++ struct gb_interface *intf = bundle->intf;
++
++ if (WARN_ON_ONCE(flags & GB_CONNECTION_FLAG_CORE_MASK))
++ flags &= ~GB_CONNECTION_FLAG_CORE_MASK;
++
++ return _gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
++ handler, flags);
++}
++EXPORT_SYMBOL_GPL(gb_connection_create_flags);
++
++struct gb_connection *
++gb_connection_create_offloaded(struct gb_bundle *bundle, u16 cport_id,
++ unsigned long flags)
++{
++ flags |= GB_CONNECTION_FLAG_OFFLOADED;
++
++ return gb_connection_create_flags(bundle, cport_id, NULL, flags);
++}
++EXPORT_SYMBOL_GPL(gb_connection_create_offloaded);
++
++static int gb_connection_hd_cport_enable(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->cport_enable)
++ return 0;
++
++ ret = hd->driver->cport_enable(hd, connection->hd_cport_id,
++ connection->flags);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to enable host cport: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void gb_connection_hd_cport_disable(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->cport_disable)
++ return;
++
++ ret = hd->driver->cport_disable(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to disable host cport: %d\n",
++ connection->name, ret);
++ }
++}
++
++static int gb_connection_hd_cport_connected(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->cport_connected)
++ return 0;
++
++ ret = hd->driver->cport_connected(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to set connected state: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_connection_hd_cport_flush(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->cport_flush)
++ return 0;
++
++ ret = hd->driver->cport_flush(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to flush host cport: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_connection_hd_cport_quiesce(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ size_t peer_space;
++ int ret;
++
++ peer_space = sizeof(struct gb_operation_msg_hdr) +
++ sizeof(struct gb_cport_shutdown_request);
++
++ if (connection->mode_switch)
++ peer_space += sizeof(struct gb_operation_msg_hdr);
++
++ ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id,
++ peer_space,
++ GB_CONNECTION_CPORT_QUIESCE_TIMEOUT);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to quiesce host cport: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_connection_hd_cport_clear(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ ret = hd->driver->cport_clear(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to clear host cport: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * Request the SVC to create a connection from AP's cport to interface's
++ * cport.
++ */
++static int
++gb_connection_svc_connection_create(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ struct gb_interface *intf;
++ u8 cport_flags;
++ int ret;
++
++ if (gb_connection_is_static(connection))
++ return 0;
++
++ intf = connection->intf;
++
++ /*
++ * Enable either E2EFC or CSD, unless no flow control is requested.
++ */
++ cport_flags = GB_SVC_CPORT_FLAG_CSV_N;
++ if (gb_connection_flow_control_disabled(connection)) {
++ cport_flags |= GB_SVC_CPORT_FLAG_CSD_N;
++ } else if (gb_connection_e2efc_enabled(connection)) {
++ cport_flags |= GB_SVC_CPORT_FLAG_CSD_N |
++ GB_SVC_CPORT_FLAG_E2EFC;
++ }
++
++ ret = gb_svc_connection_create(hd->svc,
++ hd->svc->ap_intf_id,
++ connection->hd_cport_id,
++ intf->interface_id,
++ connection->intf_cport_id,
++ cport_flags);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: failed to create svc connection: %d\n",
++ connection->name, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void
++gb_connection_svc_connection_destroy(struct gb_connection *connection)
++{
++ if (gb_connection_is_static(connection))
++ return;
++
++ gb_svc_connection_destroy(connection->hd->svc,
++ connection->hd->svc->ap_intf_id,
++ connection->hd_cport_id,
++ connection->intf->interface_id,
++ connection->intf_cport_id);
++}
++
++/* Inform Interface about active CPorts */
++static int gb_connection_control_connected(struct gb_connection *connection)
++{
++ struct gb_control *control;
++ u16 cport_id = connection->intf_cport_id;
++ int ret;
++
++ if (gb_connection_is_static(connection))
++ return 0;
++
++ if (gb_connection_is_control(connection))
++ return 0;
++
++ control = connection->intf->control;
++
++ ret = gb_control_connected_operation(control, cport_id);
++ if (ret) {
++ dev_err(&connection->bundle->dev,
++ "failed to connect cport: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void
++gb_connection_control_disconnecting(struct gb_connection *connection)
++{
++ struct gb_control *control;
++ u16 cport_id = connection->intf_cport_id;
++ int ret;
++
++ if (gb_connection_is_static(connection))
++ return;
++
++ control = connection->intf->control;
++
++ ret = gb_control_disconnecting_operation(control, cport_id);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: failed to send disconnecting: %d\n",
++ connection->name, ret);
++ }
++}
++
++static void
++gb_connection_control_disconnected(struct gb_connection *connection)
++{
++ struct gb_control *control;
++ u16 cport_id = connection->intf_cport_id;
++ int ret;
++
++ if (gb_connection_is_static(connection))
++ return;
++
++ control = connection->intf->control;
++
++ if (gb_connection_is_control(connection)) {
++ if (connection->mode_switch) {
++ ret = gb_control_mode_switch_operation(control);
++ if (ret) {
++ /*
++ * Allow mode switch to time out waiting for
++ * mailbox event.
++ */
++ return;
++ }
++ }
++
++ return;
++ }
++
++ ret = gb_control_disconnected_operation(control, cport_id);
++ if (ret) {
++ dev_warn(&connection->bundle->dev,
++ "failed to disconnect cport: %d\n", ret);
++ }
++}
++
++static int gb_connection_shutdown_operation(struct gb_connection *connection,
++ u8 phase)
++{
++ struct gb_cport_shutdown_request *req;
++ struct gb_operation *operation;
++ int ret;
++
++ operation = gb_operation_create_core(connection,
++ GB_REQUEST_TYPE_CPORT_SHUTDOWN,
++ sizeof(*req), 0, 0,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ req = operation->request->payload;
++ req->phase = phase;
++
++ ret = gb_operation_request_send_sync(operation);
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static int gb_connection_cport_shutdown(struct gb_connection *connection,
++ u8 phase)
++{
++ struct gb_host_device *hd = connection->hd;
++ const struct gb_hd_driver *drv = hd->driver;
++ int ret;
++
++ if (gb_connection_is_static(connection))
++ return 0;
++
++ if (gb_connection_is_offloaded(connection)) {
++ if (!drv->cport_shutdown)
++ return 0;
++
++ ret = drv->cport_shutdown(hd, connection->hd_cport_id, phase,
++ GB_OPERATION_TIMEOUT_DEFAULT);
++ } else {
++ ret = gb_connection_shutdown_operation(connection, phase);
++ }
++
++ if (ret) {
++ dev_err(&hd->dev, "%s: failed to send cport shutdown (phase %d): %d\n",
++ connection->name, phase, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int
++gb_connection_cport_shutdown_phase_1(struct gb_connection *connection)
++{
++ return gb_connection_cport_shutdown(connection, 1);
++}
++
++static int
++gb_connection_cport_shutdown_phase_2(struct gb_connection *connection)
++{
++ return gb_connection_cport_shutdown(connection, 2);
++}
++
++/*
++ * Cancel all active operations on a connection.
++ *
++ * Locking: Called with connection lock held and state set to DISABLED or
++ * DISCONNECTING.
++ */
++static void gb_connection_cancel_operations(struct gb_connection *connection,
++ int errno)
++ __must_hold(&connection->lock)
++{
++ struct gb_operation *operation;
++
++ while (!list_empty(&connection->operations)) {
++ operation = list_last_entry(&connection->operations,
++ struct gb_operation, links);
++ gb_operation_get(operation);
++ spin_unlock_irq(&connection->lock);
++
++ if (gb_operation_is_incoming(operation))
++ gb_operation_cancel_incoming(operation, errno);
++ else
++ gb_operation_cancel(operation, errno);
++
++ gb_operation_put(operation);
++
++ spin_lock_irq(&connection->lock);
++ }
++}
++
++/*
++ * Cancel all active incoming operations on a connection.
++ *
++ * Locking: Called with connection lock held and state set to ENABLED_TX.
++ */
++static void
++gb_connection_flush_incoming_operations(struct gb_connection *connection,
++ int errno)
++ __must_hold(&connection->lock)
++{
++ struct gb_operation *operation;
++ bool incoming;
++
++ while (!list_empty(&connection->operations)) {
++ incoming = false;
++ list_for_each_entry(operation, &connection->operations,
++ links) {
++ if (gb_operation_is_incoming(operation)) {
++ gb_operation_get(operation);
++ incoming = true;
++ break;
++ }
++ }
++
++ if (!incoming)
++ break;
++
++ spin_unlock_irq(&connection->lock);
++
++ /* FIXME: flush, not cancel? */
++ gb_operation_cancel_incoming(operation, errno);
++ gb_operation_put(operation);
++
++ spin_lock_irq(&connection->lock);
++ }
++}
++
++/*
++ * _gb_connection_enable() - enable a connection
++ * @connection: connection to enable
++ * @rx: whether to enable incoming requests
++ *
++ * Connection-enable helper for DISABLED->ENABLED, DISABLED->ENABLED_TX, and
++ * ENABLED_TX->ENABLED state transitions.
++ *
++ * Locking: Caller holds connection->mutex.
++ */
++static int _gb_connection_enable(struct gb_connection *connection, bool rx)
++{
++ int ret;
++
++ /* Handle ENABLED_TX -> ENABLED transitions. */
++ if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {
++ if (!(connection->handler && rx))
++ return 0;
++
++ spin_lock_irq(&connection->lock);
++ connection->state = GB_CONNECTION_STATE_ENABLED;
++ spin_unlock_irq(&connection->lock);
++
++ return 0;
++ }
++
++ ret = gb_connection_hd_cport_enable(connection);
++ if (ret)
++ return ret;
++
++ ret = gb_connection_svc_connection_create(connection);
++ if (ret)
++ goto err_hd_cport_clear;
++
++ ret = gb_connection_hd_cport_connected(connection);
++ if (ret)
++ goto err_svc_connection_destroy;
++
++ spin_lock_irq(&connection->lock);
++ if (connection->handler && rx)
++ connection->state = GB_CONNECTION_STATE_ENABLED;
++ else
++ connection->state = GB_CONNECTION_STATE_ENABLED_TX;
++ spin_unlock_irq(&connection->lock);
++
++ ret = gb_connection_control_connected(connection);
++ if (ret)
++ goto err_control_disconnecting;
++
++ return 0;
++
++err_control_disconnecting:
++ spin_lock_irq(&connection->lock);
++ connection->state = GB_CONNECTION_STATE_DISCONNECTING;
++ gb_connection_cancel_operations(connection, -ESHUTDOWN);
++ spin_unlock_irq(&connection->lock);
++
++ /* Transmit queue should already be empty. */
++ gb_connection_hd_cport_flush(connection);
++
++ gb_connection_control_disconnecting(connection);
++ gb_connection_cport_shutdown_phase_1(connection);
++ gb_connection_hd_cport_quiesce(connection);
++ gb_connection_cport_shutdown_phase_2(connection);
++ gb_connection_control_disconnected(connection);
++ connection->state = GB_CONNECTION_STATE_DISABLED;
++err_svc_connection_destroy:
++ gb_connection_svc_connection_destroy(connection);
++err_hd_cport_clear:
++ gb_connection_hd_cport_clear(connection);
++
++ gb_connection_hd_cport_disable(connection);
++
++ return ret;
++}
++
++int gb_connection_enable(struct gb_connection *connection)
++{
++ int ret = 0;
++
++ mutex_lock(&connection->mutex);
++
++ if (connection->state == GB_CONNECTION_STATE_ENABLED)
++ goto out_unlock;
++
++ ret = _gb_connection_enable(connection, true);
++ if (!ret)
++ trace_gb_connection_enable(connection);
++
++out_unlock:
++ mutex_unlock(&connection->mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_connection_enable);
++
++int gb_connection_enable_tx(struct gb_connection *connection)
++{
++ int ret = 0;
++
++ mutex_lock(&connection->mutex);
++
++ if (connection->state == GB_CONNECTION_STATE_ENABLED) {
++ ret = -EINVAL;
++ goto out_unlock;
++ }
++
++ if (connection->state == GB_CONNECTION_STATE_ENABLED_TX)
++ goto out_unlock;
++
++ ret = _gb_connection_enable(connection, false);
++ if (!ret)
++ trace_gb_connection_enable(connection);
++
++out_unlock:
++ mutex_unlock(&connection->mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_connection_enable_tx);
++
++void gb_connection_disable_rx(struct gb_connection *connection)
++{
++ mutex_lock(&connection->mutex);
++
++ spin_lock_irq(&connection->lock);
++ if (connection->state != GB_CONNECTION_STATE_ENABLED) {
++ spin_unlock_irq(&connection->lock);
++ goto out_unlock;
++ }
++ connection->state = GB_CONNECTION_STATE_ENABLED_TX;
++ gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);
++ spin_unlock_irq(&connection->lock);
++
++ trace_gb_connection_disable(connection);
++
++out_unlock:
++ mutex_unlock(&connection->mutex);
++}
++EXPORT_SYMBOL_GPL(gb_connection_disable_rx);
++
++void gb_connection_mode_switch_prepare(struct gb_connection *connection)
++{
++ connection->mode_switch = true;
++}
++
++void gb_connection_mode_switch_complete(struct gb_connection *connection)
++{
++ gb_connection_svc_connection_destroy(connection);
++ gb_connection_hd_cport_clear(connection);
++
++ gb_connection_hd_cport_disable(connection);
++
++ connection->mode_switch = false;
++}
++
++void gb_connection_disable(struct gb_connection *connection)
++{
++ mutex_lock(&connection->mutex);
++
++ if (connection->state == GB_CONNECTION_STATE_DISABLED)
++ goto out_unlock;
++
++ trace_gb_connection_disable(connection);
++
++ spin_lock_irq(&connection->lock);
++ connection->state = GB_CONNECTION_STATE_DISCONNECTING;
++ gb_connection_cancel_operations(connection, -ESHUTDOWN);
++ spin_unlock_irq(&connection->lock);
++
++ gb_connection_hd_cport_flush(connection);
++
++ gb_connection_control_disconnecting(connection);
++ gb_connection_cport_shutdown_phase_1(connection);
++ gb_connection_hd_cport_quiesce(connection);
++ gb_connection_cport_shutdown_phase_2(connection);
++ gb_connection_control_disconnected(connection);
++
++ connection->state = GB_CONNECTION_STATE_DISABLED;
++
++ /* control-connection tear down is deferred when mode switching */
++ if (!connection->mode_switch) {
++ gb_connection_svc_connection_destroy(connection);
++ gb_connection_hd_cport_clear(connection);
++
++ gb_connection_hd_cport_disable(connection);
++ }
++
++out_unlock:
++ mutex_unlock(&connection->mutex);
++}
++EXPORT_SYMBOL_GPL(gb_connection_disable);
++
++/* Disable a connection without communicating with the remote end. */
++void gb_connection_disable_forced(struct gb_connection *connection)
++{
++ mutex_lock(&connection->mutex);
++
++ if (connection->state == GB_CONNECTION_STATE_DISABLED)
++ goto out_unlock;
++
++ trace_gb_connection_disable(connection);
++
++ spin_lock_irq(&connection->lock);
++ connection->state = GB_CONNECTION_STATE_DISABLED;
++ gb_connection_cancel_operations(connection, -ESHUTDOWN);
++ spin_unlock_irq(&connection->lock);
++
++ gb_connection_hd_cport_flush(connection);
++
++ gb_connection_svc_connection_destroy(connection);
++ gb_connection_hd_cport_clear(connection);
++
++ gb_connection_hd_cport_disable(connection);
++out_unlock:
++ mutex_unlock(&connection->mutex);
++}
++EXPORT_SYMBOL_GPL(gb_connection_disable_forced);
++
++/* Caller must have disabled the connection before destroying it. */
++void gb_connection_destroy(struct gb_connection *connection)
++{
++ if (!connection)
++ return;
++
++ if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
++ gb_connection_disable(connection);
++
++ mutex_lock(&gb_connection_mutex);
++
++ spin_lock_irq(&gb_connections_lock);
++ list_del(&connection->bundle_links);
++ list_del(&connection->hd_links);
++ spin_unlock_irq(&gb_connections_lock);
++
++ destroy_workqueue(connection->wq);
++
++ gb_hd_cport_release(connection->hd, connection->hd_cport_id);
++ connection->hd_cport_id = CPORT_ID_BAD;
++
++ mutex_unlock(&gb_connection_mutex);
++
++ gb_connection_put(connection);
++}
++EXPORT_SYMBOL_GPL(gb_connection_destroy);
++
++void gb_connection_latency_tag_enable(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->latency_tag_enable)
++ return;
++
++ ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: failed to enable latency tag: %d\n",
++ connection->name, ret);
++ }
++}
++EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);
++
++void gb_connection_latency_tag_disable(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++ int ret;
++
++ if (!hd->driver->latency_tag_disable)
++ return;
++
++ ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: failed to disable latency tag: %d\n",
++ connection->name, ret);
++ }
++}
++EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);
+--- /dev/null
++++ b/drivers/greybus/connection.h
+@@ -0,0 +1,129 @@
++/*
++ * Greybus connections
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __CONNECTION_H
++#define __CONNECTION_H
++
++#include <linux/list.h>
++#include <linux/kfifo.h>
++
++#define GB_CONNECTION_FLAG_CSD BIT(0)
++#define GB_CONNECTION_FLAG_NO_FLOWCTRL BIT(1)
++#define GB_CONNECTION_FLAG_OFFLOADED BIT(2)
++#define GB_CONNECTION_FLAG_CDSI1 BIT(3)
++#define GB_CONNECTION_FLAG_CONTROL BIT(4)
++#define GB_CONNECTION_FLAG_HIGH_PRIO BIT(5)
++
++#define GB_CONNECTION_FLAG_CORE_MASK GB_CONNECTION_FLAG_CONTROL
++
++enum gb_connection_state {
++ GB_CONNECTION_STATE_DISABLED = 0,
++ GB_CONNECTION_STATE_ENABLED_TX = 1,
++ GB_CONNECTION_STATE_ENABLED = 2,
++ GB_CONNECTION_STATE_DISCONNECTING = 3,
++};
++
++struct gb_operation;
++
++typedef int (*gb_request_handler_t)(struct gb_operation *);
++
++struct gb_connection {
++ struct gb_host_device *hd;
++ struct gb_interface *intf;
++ struct gb_bundle *bundle;
++ struct kref kref;
++ u16 hd_cport_id;
++ u16 intf_cport_id;
++
++ struct list_head hd_links;
++ struct list_head bundle_links;
++
++ gb_request_handler_t handler;
++ unsigned long flags;
++
++ struct mutex mutex;
++ spinlock_t lock;
++ enum gb_connection_state state;
++ struct list_head operations;
++
++ char name[16];
++ struct workqueue_struct *wq;
++
++ atomic_t op_cycle;
++
++ void *private;
++
++ bool mode_switch;
++};
++
++struct gb_connection *gb_connection_create_static(struct gb_host_device *hd,
++ u16 hd_cport_id, gb_request_handler_t handler);
++struct gb_connection *gb_connection_create_control(struct gb_interface *intf);
++struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
++ u16 cport_id, gb_request_handler_t handler);
++struct gb_connection *gb_connection_create_flags(struct gb_bundle *bundle,
++ u16 cport_id, gb_request_handler_t handler,
++ unsigned long flags);
++struct gb_connection *gb_connection_create_offloaded(struct gb_bundle *bundle,
++ u16 cport_id, unsigned long flags);
++void gb_connection_destroy(struct gb_connection *connection);
++
++static inline bool gb_connection_is_static(struct gb_connection *connection)
++{
++ return !connection->intf;
++}
++
++int gb_connection_enable(struct gb_connection *connection);
++int gb_connection_enable_tx(struct gb_connection *connection);
++void gb_connection_disable_rx(struct gb_connection *connection);
++void gb_connection_disable(struct gb_connection *connection);
++void gb_connection_disable_forced(struct gb_connection *connection);
++
++void gb_connection_mode_switch_prepare(struct gb_connection *connection);
++void gb_connection_mode_switch_complete(struct gb_connection *connection);
++
++void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
++ u8 *data, size_t length);
++
++void gb_connection_latency_tag_enable(struct gb_connection *connection);
++void gb_connection_latency_tag_disable(struct gb_connection *connection);
++
++static inline bool gb_connection_e2efc_enabled(struct gb_connection *connection)
++{
++ return !(connection->flags & GB_CONNECTION_FLAG_CSD);
++}
++
++static inline bool
++gb_connection_flow_control_disabled(struct gb_connection *connection)
++{
++ return connection->flags & GB_CONNECTION_FLAG_NO_FLOWCTRL;
++}
++
++static inline bool gb_connection_is_offloaded(struct gb_connection *connection)
++{
++ return connection->flags & GB_CONNECTION_FLAG_OFFLOADED;
++}
++
++static inline bool gb_connection_is_control(struct gb_connection *connection)
++{
++ return connection->flags & GB_CONNECTION_FLAG_CONTROL;
++}
++
++static inline void *gb_connection_get_data(struct gb_connection *connection)
++{
++ return connection->private;
++}
++
++static inline void gb_connection_set_data(struct gb_connection *connection,
++ void *data)
++{
++ connection->private = data;
++}
++
++#endif /* __CONNECTION_H */
+--- /dev/null
++++ b/drivers/greybus/control.c
+@@ -0,0 +1,635 @@
++/*
++ * Greybus CPort control protocol.
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include "greybus.h"
++
++/* Highest control-protocol version supported */
++#define GB_CONTROL_VERSION_MAJOR 0
++#define GB_CONTROL_VERSION_MINOR 1
++
++
++static int gb_control_get_version(struct gb_control *control)
++{
++ struct gb_interface *intf = control->connection->intf;
++ struct gb_control_version_request request;
++ struct gb_control_version_response response;
++ int ret;
++
++ request.major = GB_CONTROL_VERSION_MAJOR;
++ request.minor = GB_CONTROL_VERSION_MINOR;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_VERSION,
++ &request, sizeof(request), &response,
++ sizeof(response));
++ if (ret) {
++ dev_err(&intf->dev,
++ "failed to get control-protocol version: %d\n",
++ ret);
++ return ret;
++ }
++
++ if (response.major > request.major) {
++ dev_err(&intf->dev,
++ "unsupported major control-protocol version (%u > %u)\n",
++ response.major, request.major);
++ return -ENOTSUPP;
++ }
++
++ control->protocol_major = response.major;
++ control->protocol_minor = response.minor;
++
++ dev_dbg(&intf->dev, "%s - %u.%u\n", __func__, response.major,
++ response.minor);
++
++ return 0;
++}
++
++static int gb_control_get_bundle_version(struct gb_control *control,
++ struct gb_bundle *bundle)
++{
++ struct gb_interface *intf = control->connection->intf;
++ struct gb_control_bundle_version_request request;
++ struct gb_control_bundle_version_response response;
++ int ret;
++
++ request.bundle_id = bundle->id;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_BUNDLE_VERSION,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&intf->dev,
++ "failed to get bundle %u class version: %d\n",
++ bundle->id, ret);
++ return ret;
++ }
++
++ bundle->class_major = response.major;
++ bundle->class_minor = response.minor;
++
++ dev_dbg(&intf->dev, "%s - %u: %u.%u\n", __func__, bundle->id,
++ response.major, response.minor);
++
++ return 0;
++}
++
++int gb_control_get_bundle_versions(struct gb_control *control)
++{
++ struct gb_interface *intf = control->connection->intf;
++ struct gb_bundle *bundle;
++ int ret;
++
++ if (!control->has_bundle_version)
++ return 0;
++
++ list_for_each_entry(bundle, &intf->bundles, links) {
++ ret = gb_control_get_bundle_version(control, bundle);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++/* Get Manifest's size from the interface */
++int gb_control_get_manifest_size_operation(struct gb_interface *intf)
++{
++ struct gb_control_get_manifest_size_response response;
++ struct gb_connection *connection = intf->control->connection;
++ int ret;
++
++ ret = gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST_SIZE,
++ NULL, 0, &response, sizeof(response));
++ if (ret) {
++ dev_err(&connection->intf->dev,
++ "failed to get manifest size: %d\n", ret);
++ return ret;
++ }
++
++ return le16_to_cpu(response.size);
++}
++
++/* Reads Manifest from the interface */
++int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
++ size_t size)
++{
++ struct gb_connection *connection = intf->control->connection;
++
++ return gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST,
++ NULL, 0, manifest, size);
++}
++
++int gb_control_connected_operation(struct gb_control *control, u16 cport_id)
++{
++ struct gb_control_connected_request request;
++
++ request.cport_id = cpu_to_le16(cport_id);
++ return gb_operation_sync(control->connection, GB_CONTROL_TYPE_CONNECTED,
++ &request, sizeof(request), NULL, 0);
++}
++
++int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id)
++{
++ struct gb_control_disconnected_request request;
++
++ request.cport_id = cpu_to_le16(cport_id);
++ return gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_DISCONNECTED, &request,
++ sizeof(request), NULL, 0);
++}
++
++int gb_control_disconnecting_operation(struct gb_control *control,
++ u16 cport_id)
++{
++ struct gb_control_disconnecting_request *request;
++ struct gb_operation *operation;
++ int ret;
++
++ operation = gb_operation_create_core(control->connection,
++ GB_CONTROL_TYPE_DISCONNECTING,
++ sizeof(*request), 0, 0,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ request = operation->request->payload;
++ request->cport_id = cpu_to_le16(cport_id);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret) {
++ dev_err(&control->dev, "failed to send disconnecting: %d\n",
++ ret);
++ }
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++int gb_control_mode_switch_operation(struct gb_control *control)
++{
++ struct gb_operation *operation;
++ int ret;
++
++ operation = gb_operation_create_core(control->connection,
++ GB_CONTROL_TYPE_MODE_SWITCH,
++ 0, 0, GB_OPERATION_FLAG_UNIDIRECTIONAL,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret)
++ dev_err(&control->dev, "failed to send mode switch: %d\n", ret);
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++int gb_control_timesync_enable(struct gb_control *control, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk)
++{
++ struct gb_control_timesync_enable_request request;
++
++ request.count = count;
++ request.frame_time = cpu_to_le64(frame_time);
++ request.strobe_delay = cpu_to_le32(strobe_delay);
++ request.refclk = cpu_to_le32(refclk);
++ return gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_TIMESYNC_ENABLE, &request,
++ sizeof(request), NULL, 0);
++}
++
++int gb_control_timesync_disable(struct gb_control *control)
++{
++ return gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_TIMESYNC_DISABLE, NULL, 0,
++ NULL, 0);
++}
++
++int gb_control_timesync_get_last_event(struct gb_control *control,
++ u64 *frame_time)
++{
++ struct gb_control_timesync_get_last_event_response response;
++ int ret;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_TIMESYNC_GET_LAST_EVENT,
++ NULL, 0, &response, sizeof(response));
++ if (!ret)
++ *frame_time = le64_to_cpu(response.frame_time);
++ return ret;
++}
++
++int gb_control_timesync_authoritative(struct gb_control *control,
++ u64 *frame_time)
++{
++ struct gb_control_timesync_authoritative_request request;
++ int i;
++
++ for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
++ request.frame_time[i] = cpu_to_le64(frame_time[i]);
++
++ return gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_TIMESYNC_AUTHORITATIVE,
++ &request, sizeof(request),
++ NULL, 0);
++}
++
++static int gb_control_bundle_pm_status_map(u8 status)
++{
++ switch (status) {
++ case GB_CONTROL_BUNDLE_PM_INVAL:
++ return -EINVAL;
++ case GB_CONTROL_BUNDLE_PM_BUSY:
++ return -EBUSY;
++ case GB_CONTROL_BUNDLE_PM_NA:
++ return -ENOMSG;
++ case GB_CONTROL_BUNDLE_PM_FAIL:
++ default:
++ return -EREMOTEIO;
++ }
++}
++
++int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id)
++{
++ struct gb_control_bundle_pm_request request;
++ struct gb_control_bundle_pm_response response;
++ int ret;
++
++ request.bundle_id = bundle_id;
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_BUNDLE_SUSPEND, &request,
++ sizeof(request), &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev, "failed to send bundle %u suspend: %d\n",
++ bundle_id, ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
++ dev_err(&control->dev, "failed to suspend bundle %u: %d\n",
++ bundle_id, response.status);
++ return gb_control_bundle_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id)
++{
++ struct gb_control_bundle_pm_request request;
++ struct gb_control_bundle_pm_response response;
++ int ret;
++
++ request.bundle_id = bundle_id;
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_BUNDLE_RESUME, &request,
++ sizeof(request), &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev, "failed to send bundle %u resume: %d\n",
++ bundle_id, ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
++ dev_err(&control->dev, "failed to resume bundle %u: %d\n",
++ bundle_id, response.status);
++ return gb_control_bundle_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id)
++{
++ struct gb_control_bundle_pm_request request;
++ struct gb_control_bundle_pm_response response;
++ int ret;
++
++ request.bundle_id = bundle_id;
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_BUNDLE_DEACTIVATE, &request,
++ sizeof(request), &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev,
++ "failed to send bundle %u deactivate: %d\n", bundle_id,
++ ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
++ dev_err(&control->dev, "failed to deactivate bundle %u: %d\n",
++ bundle_id, response.status);
++ return gb_control_bundle_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++int gb_control_bundle_activate(struct gb_control *control, u8 bundle_id)
++{
++ struct gb_control_bundle_pm_request request;
++ struct gb_control_bundle_pm_response response;
++ int ret;
++
++ if (!control->has_bundle_activate)
++ return 0;
++
++ request.bundle_id = bundle_id;
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_BUNDLE_ACTIVATE, &request,
++ sizeof(request), &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev,
++ "failed to send bundle %u activate: %d\n", bundle_id,
++ ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
++ dev_err(&control->dev, "failed to activate bundle %u: %d\n",
++ bundle_id, response.status);
++ return gb_control_bundle_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++static int gb_control_interface_pm_status_map(u8 status)
++{
++ switch (status) {
++ case GB_CONTROL_INTF_PM_BUSY:
++ return -EBUSY;
++ case GB_CONTROL_INTF_PM_NA:
++ return -ENOMSG;
++ default:
++ return -EREMOTEIO;
++ }
++}
++
++int gb_control_interface_suspend_prepare(struct gb_control *control)
++{
++ struct gb_control_intf_pm_response response;
++ int ret;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE, NULL, 0,
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev,
++ "failed to send interface suspend prepare: %d\n", ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_INTF_PM_OK) {
++ dev_err(&control->dev, "interface error while preparing suspend: %d\n",
++ response.status);
++ return gb_control_interface_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++int gb_control_interface_deactivate_prepare(struct gb_control *control)
++{
++ struct gb_control_intf_pm_response response;
++ int ret;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_INTF_DEACTIVATE_PREPARE, NULL,
++ 0, &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev, "failed to send interface deactivate prepare: %d\n",
++ ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_INTF_PM_OK) {
++ dev_err(&control->dev, "interface error while preparing deactivate: %d\n",
++ response.status);
++ return gb_control_interface_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++int gb_control_interface_hibernate_abort(struct gb_control *control)
++{
++ struct gb_control_intf_pm_response response;
++ int ret;
++
++ ret = gb_operation_sync(control->connection,
++ GB_CONTROL_TYPE_INTF_HIBERNATE_ABORT, NULL, 0,
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&control->dev,
++ "failed to send interface aborting hibernate: %d\n",
++ ret);
++ return ret;
++ }
++
++ if (response.status != GB_CONTROL_INTF_PM_OK) {
++ dev_err(&control->dev, "interface error while aborting hibernate: %d\n",
++ response.status);
++ return gb_control_interface_pm_status_map(response.status);
++ }
++
++ return 0;
++}
++
++static ssize_t vendor_string_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_control *control = to_gb_control(dev);
++
++ return scnprintf(buf, PAGE_SIZE, "%s\n", control->vendor_string);
++}
++static DEVICE_ATTR_RO(vendor_string);
++
++static ssize_t product_string_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_control *control = to_gb_control(dev);
++
++ return scnprintf(buf, PAGE_SIZE, "%s\n", control->product_string);
++}
++static DEVICE_ATTR_RO(product_string);
++
++static struct attribute *control_attrs[] = {
++ &dev_attr_vendor_string.attr,
++ &dev_attr_product_string.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(control);
++
++static void gb_control_release(struct device *dev)
++{
++ struct gb_control *control = to_gb_control(dev);
++
++ gb_connection_destroy(control->connection);
++
++ kfree(control->vendor_string);
++ kfree(control->product_string);
++
++ kfree(control);
++}
++
++struct device_type greybus_control_type = {
++ .name = "greybus_control",
++ .release = gb_control_release,
++};
++
++struct gb_control *gb_control_create(struct gb_interface *intf)
++{
++ struct gb_connection *connection;
++ struct gb_control *control;
++
++ control = kzalloc(sizeof(*control), GFP_KERNEL);
++ if (!control)
++ return ERR_PTR(-ENOMEM);
++
++ control->intf = intf;
++
++ connection = gb_connection_create_control(intf);
++ if (IS_ERR(connection)) {
++ dev_err(&intf->dev,
++ "failed to create control connection: %ld\n",
++ PTR_ERR(connection));
++ kfree(control);
++ return ERR_CAST(connection);
++ }
++
++ control->connection = connection;
++
++ control->dev.parent = &intf->dev;
++ control->dev.bus = &greybus_bus_type;
++ control->dev.type = &greybus_control_type;
++ control->dev.groups = control_groups;
++ control->dev.dma_mask = intf->dev.dma_mask;
++ device_initialize(&control->dev);
++ dev_set_name(&control->dev, "%s.ctrl", dev_name(&intf->dev));
++
++ gb_connection_set_data(control->connection, control);
++
++ return control;
++}
++
++int gb_control_enable(struct gb_control *control)
++{
++ int ret;
++
++ dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
++
++ ret = gb_connection_enable_tx(control->connection);
++ if (ret) {
++ dev_err(&control->connection->intf->dev,
++ "failed to enable control connection: %d\n",
++ ret);
++ return ret;
++ }
++
++ ret = gb_control_get_version(control);
++ if (ret)
++ goto err_disable_connection;
++
++ if (control->protocol_major > 0 || control->protocol_minor > 1)
++ control->has_bundle_version = true;
++
++ /* FIXME: use protocol version instead */
++ if (!(control->intf->quirks & GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE))
++ control->has_bundle_activate = true;
++
++ return 0;
++
++err_disable_connection:
++ gb_connection_disable(control->connection);
++
++ return ret;
++}
++
++void gb_control_disable(struct gb_control *control)
++{
++ dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
++
++ if (control->intf->disconnected)
++ gb_connection_disable_forced(control->connection);
++ else
++ gb_connection_disable(control->connection);
++}
++
++int gb_control_suspend(struct gb_control *control)
++{
++ gb_connection_disable(control->connection);
++
++ return 0;
++}
++
++int gb_control_resume(struct gb_control *control)
++{
++ int ret;
++
++ ret = gb_connection_enable_tx(control->connection);
++ if (ret) {
++ dev_err(&control->connection->intf->dev,
++ "failed to enable control connection: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++int gb_control_add(struct gb_control *control)
++{
++ int ret;
++
++ ret = device_add(&control->dev);
++ if (ret) {
++ dev_err(&control->dev,
++ "failed to register control device: %d\n",
++ ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++void gb_control_del(struct gb_control *control)
++{
++ if (device_is_registered(&control->dev))
++ device_del(&control->dev);
++}
++
++struct gb_control *gb_control_get(struct gb_control *control)
++{
++ get_device(&control->dev);
++
++ return control;
++}
++
++void gb_control_put(struct gb_control *control)
++{
++ put_device(&control->dev);
++}
++
++void gb_control_mode_switch_prepare(struct gb_control *control)
++{
++ gb_connection_mode_switch_prepare(control->connection);
++}
++
++void gb_control_mode_switch_complete(struct gb_control *control)
++{
++ gb_connection_mode_switch_complete(control->connection);
++}
+--- /dev/null
++++ b/drivers/greybus/control.h
+@@ -0,0 +1,65 @@
++/*
++ * Greybus CPort control protocol
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __CONTROL_H
++#define __CONTROL_H
++
++struct gb_control {
++ struct device dev;
++ struct gb_interface *intf;
++
++ struct gb_connection *connection;
++
++ u8 protocol_major;
++ u8 protocol_minor;
++
++ bool has_bundle_activate;
++ bool has_bundle_version;
++
++ char *vendor_string;
++ char *product_string;
++};
++#define to_gb_control(d) container_of(d, struct gb_control, dev)
++
++struct gb_control *gb_control_create(struct gb_interface *intf);
++int gb_control_enable(struct gb_control *control);
++void gb_control_disable(struct gb_control *control);
++int gb_control_suspend(struct gb_control *control);
++int gb_control_resume(struct gb_control *control);
++int gb_control_add(struct gb_control *control);
++void gb_control_del(struct gb_control *control);
++struct gb_control *gb_control_get(struct gb_control *control);
++void gb_control_put(struct gb_control *control);
++
++int gb_control_get_bundle_versions(struct gb_control *control);
++int gb_control_connected_operation(struct gb_control *control, u16 cport_id);
++int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id);
++int gb_control_disconnecting_operation(struct gb_control *control,
++ u16 cport_id);
++int gb_control_mode_switch_operation(struct gb_control *control);
++void gb_control_mode_switch_prepare(struct gb_control *control);
++void gb_control_mode_switch_complete(struct gb_control *control);
++int gb_control_get_manifest_size_operation(struct gb_interface *intf);
++int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
++ size_t size);
++int gb_control_timesync_enable(struct gb_control *control, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk);
++int gb_control_timesync_disable(struct gb_control *control);
++int gb_control_timesync_get_last_event(struct gb_control *control,
++ u64 *frame_time);
++int gb_control_timesync_authoritative(struct gb_control *control,
++ u64 *frame_time);
++int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id);
++int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id);
++int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id);
++int gb_control_bundle_activate(struct gb_control *control, u8 bundle_id);
++int gb_control_interface_suspend_prepare(struct gb_control *control);
++int gb_control_interface_deactivate_prepare(struct gb_control *control);
++int gb_control_interface_hibernate_abort(struct gb_control *control);
++#endif /* __CONTROL_H */
+--- /dev/null
++++ b/drivers/greybus/core.c
+@@ -0,0 +1,361 @@
++/*
++ * Greybus "Core"
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#define CREATE_TRACE_POINTS
++#include "greybus.h"
++#include "greybus_trace.h"
++
++#define GB_BUNDLE_AUTOSUSPEND_MS 3000
++
++/* Allow greybus to be disabled at boot if needed */
++static bool nogreybus;
++#ifdef MODULE
++module_param(nogreybus, bool, 0444);
++#else
++core_param(nogreybus, nogreybus, bool, 0444);
++#endif
++int greybus_disabled(void)
++{
++ return nogreybus;
++}
++EXPORT_SYMBOL_GPL(greybus_disabled);
++
++static bool greybus_match_one_id(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
++ (id->vendor != bundle->intf->vendor_id))
++ return false;
++
++ if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
++ (id->product != bundle->intf->product_id))
++ return false;
++
++ if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
++ (id->class != bundle->class))
++ return false;
++
++ return true;
++}
++
++static const struct greybus_bundle_id *
++greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
++{
++ if (id == NULL)
++ return NULL;
++
++ for (; id->vendor || id->product || id->class || id->driver_info;
++ id++) {
++ if (greybus_match_one_id(bundle, id))
++ return id;
++ }
++
++ return NULL;
++}
++
++static int greybus_match_device(struct device *dev, struct device_driver *drv)
++{
++ struct greybus_driver *driver = to_greybus_driver(drv);
++ struct gb_bundle *bundle;
++ const struct greybus_bundle_id *id;
++
++ if (!is_gb_bundle(dev))
++ return 0;
++
++ bundle = to_gb_bundle(dev);
++
++ id = greybus_match_id(bundle, driver->id_table);
++ if (id)
++ return 1;
++ /* FIXME - Dynamic ids? */
++ return 0;
++}
++
++static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++ struct gb_host_device *hd;
++ struct gb_module *module = NULL;
++ struct gb_interface *intf = NULL;
++ struct gb_control *control = NULL;
++ struct gb_bundle *bundle = NULL;
++ struct gb_svc *svc = NULL;
++
++ if (is_gb_host_device(dev)) {
++ hd = to_gb_host_device(dev);
++ } else if (is_gb_module(dev)) {
++ module = to_gb_module(dev);
++ hd = module->hd;
++ } else if (is_gb_interface(dev)) {
++ intf = to_gb_interface(dev);
++ module = intf->module;
++ hd = intf->hd;
++ } else if (is_gb_control(dev)) {
++ control = to_gb_control(dev);
++ intf = control->intf;
++ module = intf->module;
++ hd = intf->hd;
++ } else if (is_gb_bundle(dev)) {
++ bundle = to_gb_bundle(dev);
++ intf = bundle->intf;
++ module = intf->module;
++ hd = intf->hd;
++ } else if (is_gb_svc(dev)) {
++ svc = to_gb_svc(dev);
++ hd = svc->hd;
++ } else {
++ dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
++ return -EINVAL;
++ }
++
++ if (add_uevent_var(env, "BUS=%u", hd->bus_id))
++ return -ENOMEM;
++
++ if (module) {
++ if (add_uevent_var(env, "MODULE=%u", module->module_id))
++ return -ENOMEM;
++ }
++
++ if (intf) {
++ if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
++ intf->vendor_id, intf->product_id))
++ return -ENOMEM;
++ }
++
++ if (bundle) {
++ // FIXME
++ // add a uevent that can "load" a bundle type
++ // This is what we need to bind a driver to so use the info
++ // in gmod here as well
++
++ if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void greybus_shutdown(struct device *dev)
++{
++ if (is_gb_host_device(dev)) {
++ struct gb_host_device *hd;
++
++ hd = to_gb_host_device(dev);
++ gb_hd_shutdown(hd);
++ }
++}
++
++struct bus_type greybus_bus_type = {
++ .name = "greybus",
++ .match = greybus_match_device,
++ .uevent = greybus_uevent,
++ .shutdown = greybus_shutdown,
++};
++
++static int greybus_probe(struct device *dev)
++{
++ struct greybus_driver *driver = to_greybus_driver(dev->driver);
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ const struct greybus_bundle_id *id;
++ int retval;
++
++ /* match id */
++ id = greybus_match_id(bundle, driver->id_table);
++ if (!id)
++ return -ENODEV;
++
++ retval = pm_runtime_get_sync(&bundle->intf->dev);
++ if (retval < 0) {
++ pm_runtime_put_noidle(&bundle->intf->dev);
++ return retval;
++ }
++
++ retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
++ if (retval) {
++ pm_runtime_put(&bundle->intf->dev);
++ return retval;
++ }
++
++ /*
++ * Unbound bundle devices are always deactivated. During probe, the
++ * Runtime PM is set to enabled and active and the usage count is
++ * incremented. If the driver supports runtime PM, it should call
++ * pm_runtime_put() in its probe routine and pm_runtime_get_sync()
++ * in remove routine.
++ */
++ pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
++ pm_runtime_use_autosuspend(dev);
++ pm_runtime_get_noresume(dev);
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++
++ retval = driver->probe(bundle, id);
++ if (retval) {
++ /*
++ * Catch buggy drivers that fail to destroy their connections.
++ */
++ WARN_ON(!list_empty(&bundle->connections));
++
++ gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
++
++ pm_runtime_disable(dev);
++ pm_runtime_set_suspended(dev);
++ pm_runtime_put_noidle(dev);
++ pm_runtime_dont_use_autosuspend(dev);
++ pm_runtime_put(&bundle->intf->dev);
++
++ return retval;
++ }
++
++ gb_timesync_schedule_synchronous(bundle->intf);
++
++ pm_runtime_put(&bundle->intf->dev);
++
++ return 0;
++}
++
++static int greybus_remove(struct device *dev)
++{
++ struct greybus_driver *driver = to_greybus_driver(dev->driver);
++ struct gb_bundle *bundle = to_gb_bundle(dev);
++ struct gb_connection *connection;
++ int retval;
++
++ retval = pm_runtime_get_sync(dev);
++ if (retval < 0)
++ dev_err(dev, "failed to resume bundle: %d\n", retval);
++
++ /*
++ * Disable (non-offloaded) connections early in case the interface is
++ * already gone to avoid unceccessary operation timeouts during
++ * driver disconnect. Otherwise, only disable incoming requests.
++ */
++ list_for_each_entry(connection, &bundle->connections, bundle_links) {
++ if (gb_connection_is_offloaded(connection))
++ continue;
++
++ if (bundle->intf->disconnected)
++ gb_connection_disable_forced(connection);
++ else
++ gb_connection_disable_rx(connection);
++ }
++
++ driver->disconnect(bundle);
++
++ /* Catch buggy drivers that fail to destroy their connections. */
++ WARN_ON(!list_empty(&bundle->connections));
++
++ if (!bundle->intf->disconnected)
++ gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
++
++ pm_runtime_put_noidle(dev);
++ pm_runtime_disable(dev);
++ pm_runtime_set_suspended(dev);
++ pm_runtime_dont_use_autosuspend(dev);
++ pm_runtime_put_noidle(dev);
++
++ return 0;
++}
++
++int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
++ const char *mod_name)
++{
++ int retval;
++
++ if (greybus_disabled())
++ return -ENODEV;
++
++ driver->driver.bus = &greybus_bus_type;
++ driver->driver.name = driver->name;
++ driver->driver.probe = greybus_probe;
++ driver->driver.remove = greybus_remove;
++ driver->driver.owner = owner;
++ driver->driver.mod_name = mod_name;
++
++ retval = driver_register(&driver->driver);
++ if (retval)
++ return retval;
++
++ pr_info("registered new driver %s\n", driver->name);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(greybus_register_driver);
++
++void greybus_deregister_driver(struct greybus_driver *driver)
++{
++ driver_unregister(&driver->driver);
++}
++EXPORT_SYMBOL_GPL(greybus_deregister_driver);
++
++static int __init gb_init(void)
++{
++ int retval;
++
++ if (greybus_disabled())
++ return -ENODEV;
++
++ BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
++
++ gb_debugfs_init();
++
++ retval = bus_register(&greybus_bus_type);
++ if (retval) {
++ pr_err("bus_register failed (%d)\n", retval);
++ goto error_bus;
++ }
++
++ retval = gb_hd_init();
++ if (retval) {
++ pr_err("gb_hd_init failed (%d)\n", retval);
++ goto error_hd;
++ }
++
++ retval = gb_operation_init();
++ if (retval) {
++ pr_err("gb_operation_init failed (%d)\n", retval);
++ goto error_operation;
++ }
++
++ retval = gb_timesync_init();
++ if (retval) {
++ pr_err("gb_timesync_init failed\n");
++ goto error_timesync;
++ }
++ return 0; /* Success */
++
++error_timesync:
++ gb_operation_exit();
++error_operation:
++ gb_hd_exit();
++error_hd:
++ bus_unregister(&greybus_bus_type);
++error_bus:
++ gb_debugfs_cleanup();
++
++ return retval;
++}
++module_init(gb_init);
++
++static void __exit gb_exit(void)
++{
++ gb_timesync_exit();
++ gb_operation_exit();
++ gb_hd_exit();
++ bus_unregister(&greybus_bus_type);
++ gb_debugfs_cleanup();
++ tracepoint_synchronize_unregister();
++}
++module_exit(gb_exit);
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
+--- /dev/null
++++ b/drivers/greybus/debugfs.c
+@@ -0,0 +1,31 @@
++/*
++ * Greybus debugfs code
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/debugfs.h>
++
++#include "greybus.h"
++
++static struct dentry *gb_debug_root;
++
++void __init gb_debugfs_init(void)
++{
++ gb_debug_root = debugfs_create_dir("greybus", NULL);
++}
++
++void gb_debugfs_cleanup(void)
++{
++ debugfs_remove_recursive(gb_debug_root);
++ gb_debug_root = NULL;
++}
++
++struct dentry *gb_debugfs_get(void)
++{
++ return gb_debug_root;
++}
++EXPORT_SYMBOL_GPL(gb_debugfs_get);
+--- /dev/null
++++ b/drivers/greybus/devices
+@@ -0,0 +1,11 @@
++T: Bus=01 Lev=03 Prnt=07 Port=02 Cnt=03 Dev#= 12 Spd=12 MxCh= 0
++D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
++P: Vendor=ffff ProdID=0001 Rev= 1.00
++S: Manufacturer=Greybus
++S: Product=SVC Bridge
++S: SerialNumber=12239
++C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=100mA
++I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=es1_ap_driver
++E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=64ms
++E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
++E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+--- /dev/null
++++ b/drivers/greybus/greybus.h
+@@ -0,0 +1,154 @@
++/*
++ * Greybus driver and device API
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __LINUX_GREYBUS_H
++#define __LINUX_GREYBUS_H
++
++#ifdef __KERNEL__
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <linux/idr.h>
++
++#include "greybus_id.h"
++#include "greybus_manifest.h"
++#include "greybus_protocols.h"
++#include "manifest.h"
++#include "hd.h"
++#include "svc.h"
++#include "control.h"
++#include "module.h"
++#include "interface.h"
++#include "bundle.h"
++#include "connection.h"
++#include "operation.h"
++#include "timesync.h"
++
++/* Matches up with the Greybus Protocol specification document */
++#define GREYBUS_VERSION_MAJOR 0x00
++#define GREYBUS_VERSION_MINOR 0x01
++
++#define GREYBUS_ID_MATCH_DEVICE \
++ (GREYBUS_ID_MATCH_VENDOR | GREYBUS_ID_MATCH_PRODUCT)
++
++#define GREYBUS_DEVICE(v, p) \
++ .match_flags = GREYBUS_ID_MATCH_DEVICE, \
++ .vendor = (v), \
++ .product = (p),
++
++#define GREYBUS_DEVICE_CLASS(c) \
++ .match_flags = GREYBUS_ID_MATCH_CLASS, \
++ .class = (c),
++
++/* Maximum number of CPorts */
++#define CPORT_ID_MAX 4095 /* UniPro max id is 4095 */
++#define CPORT_ID_BAD U16_MAX
++
++struct greybus_driver {
++ const char *name;
++
++ int (*probe)(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id);
++ void (*disconnect)(struct gb_bundle *bundle);
++
++ const struct greybus_bundle_id *id_table;
++
++ struct device_driver driver;
++};
++#define to_greybus_driver(d) container_of(d, struct greybus_driver, driver)
++
++static inline void greybus_set_drvdata(struct gb_bundle *bundle, void *data)
++{
++ dev_set_drvdata(&bundle->dev, data);
++}
++
++static inline void *greybus_get_drvdata(struct gb_bundle *bundle)
++{
++ return dev_get_drvdata(&bundle->dev);
++}
++
++/* Don't call these directly, use the module_greybus_driver() macro instead */
++int greybus_register_driver(struct greybus_driver *driver,
++ struct module *module, const char *mod_name);
++void greybus_deregister_driver(struct greybus_driver *driver);
++
++/* define to get proper THIS_MODULE and KBUILD_MODNAME values */
++#define greybus_register(driver) \
++ greybus_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
++#define greybus_deregister(driver) \
++ greybus_deregister_driver(driver)
++
++/**
++ * module_greybus_driver() - Helper macro for registering a Greybus driver
++ * @__greybus_driver: greybus_driver structure
++ *
++ * Helper macro for Greybus drivers to set up proper module init / exit
++ * functions. Replaces module_init() and module_exit() and keeps people from
++ * printing pointless things to the kernel log when their driver is loaded.
++ */
++#define module_greybus_driver(__greybus_driver) \
++ module_driver(__greybus_driver, greybus_register, greybus_deregister)
++
++int greybus_disabled(void);
++
++void gb_debugfs_init(void);
++void gb_debugfs_cleanup(void);
++struct dentry *gb_debugfs_get(void);
++
++extern struct bus_type greybus_bus_type;
++
++extern struct device_type greybus_hd_type;
++extern struct device_type greybus_module_type;
++extern struct device_type greybus_interface_type;
++extern struct device_type greybus_control_type;
++extern struct device_type greybus_bundle_type;
++extern struct device_type greybus_svc_type;
++
++static inline int is_gb_host_device(const struct device *dev)
++{
++ return dev->type == &greybus_hd_type;
++}
++
++static inline int is_gb_module(const struct device *dev)
++{
++ return dev->type == &greybus_module_type;
++}
++
++static inline int is_gb_interface(const struct device *dev)
++{
++ return dev->type == &greybus_interface_type;
++}
++
++static inline int is_gb_control(const struct device *dev)
++{
++ return dev->type == &greybus_control_type;
++}
++
++static inline int is_gb_bundle(const struct device *dev)
++{
++ return dev->type == &greybus_bundle_type;
++}
++
++static inline int is_gb_svc(const struct device *dev)
++{
++ return dev->type == &greybus_svc_type;
++}
++
++static inline bool cport_id_valid(struct gb_host_device *hd, u16 cport_id)
++{
++ return cport_id != CPORT_ID_BAD && cport_id < hd->num_cports;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __LINUX_GREYBUS_H */
+--- /dev/null
++++ b/drivers/greybus/greybus_authentication.h
+@@ -0,0 +1,120 @@
++/*
++ * Greybus Component Authentication User Header
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __GREYBUS_AUTHENTICATION_USER_H
++#define __GREYBUS_AUTHENTICATION_USER_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#define CAP_CERTIFICATE_MAX_SIZE 1600
++#define CAP_SIGNATURE_MAX_SIZE 320
++
++/* Certificate class types */
++#define CAP_CERT_IMS_EAPC 0x00000001
++#define CAP_CERT_IMS_EASC 0x00000002
++#define CAP_CERT_IMS_EARC 0x00000003
++#define CAP_CERT_IMS_IAPC 0x00000004
++#define CAP_CERT_IMS_IASC 0x00000005
++#define CAP_CERT_IMS_IARC 0x00000006
++
++/* IMS Certificate response result codes */
++#define CAP_IMS_RESULT_CERT_FOUND 0x00
++#define CAP_IMS_RESULT_CERT_CLASS_INVAL 0x01
++#define CAP_IMS_RESULT_CERT_CORRUPT 0x02
++#define CAP_IMS_RESULT_CERT_NOT_FOUND 0x03
++
++/* Authentication types */
++#define CAP_AUTH_IMS_PRI 0x00000001
++#define CAP_AUTH_IMS_SEC 0x00000002
++#define CAP_AUTH_IMS_RSA 0x00000003
++
++/* Authenticate response result codes */
++#define CAP_AUTH_RESULT_CR_SUCCESS 0x00
++#define CAP_AUTH_RESULT_CR_BAD_TYPE 0x01
++#define CAP_AUTH_RESULT_CR_WRONG_EP 0x02
++#define CAP_AUTH_RESULT_CR_NO_KEY 0x03
++#define CAP_AUTH_RESULT_CR_SIG_FAIL 0x04
++
++
++/* IOCTL support */
++struct cap_ioc_get_endpoint_uid {
++ __u8 uid[8];
++} __attribute__ ((__packed__));
++
++struct cap_ioc_get_ims_certificate {
++ __u32 certificate_class;
++ __u32 certificate_id;
++
++ __u8 result_code;
++ __u32 cert_size;
++ __u8 certificate[CAP_CERTIFICATE_MAX_SIZE];
++} __attribute__ ((__packed__));
++
++struct cap_ioc_authenticate {
++ __u32 auth_type;
++ __u8 uid[8];
++ __u8 challenge[32];
++
++ __u8 result_code;
++ __u8 response[64];
++ __u32 signature_size;
++ __u8 signature[CAP_SIGNATURE_MAX_SIZE];
++} __attribute__ ((__packed__));
++
++#define CAP_IOCTL_BASE 'C'
++#define CAP_IOC_GET_ENDPOINT_UID _IOR(CAP_IOCTL_BASE, 0, struct cap_ioc_get_endpoint_uid)
++#define CAP_IOC_GET_IMS_CERTIFICATE _IOWR(CAP_IOCTL_BASE, 1, struct cap_ioc_get_ims_certificate)
++#define CAP_IOC_AUTHENTICATE _IOWR(CAP_IOCTL_BASE, 2, struct cap_ioc_authenticate)
++
++#endif /* __GREYBUS_AUTHENTICATION_USER_H */
+--- /dev/null
++++ b/drivers/greybus/greybus_id.h
+@@ -0,0 +1,26 @@
++/* FIXME
++ * move this to include/linux/mod_devicetable.h when merging
++ */
++
++#ifndef __LINUX_GREYBUS_ID_H
++#define __LINUX_GREYBUS_ID_H
++
++#include <linux/types.h>
++#include <linux/mod_devicetable.h>
++
++
++struct greybus_bundle_id {
++ __u16 match_flags;
++ __u32 vendor;
++ __u32 product;
++ __u8 class;
++
++ kernel_ulong_t driver_info __aligned(sizeof(kernel_ulong_t));
++};
++
++/* Used to match the greybus_bundle_id */
++#define GREYBUS_ID_MATCH_VENDOR BIT(0)
++#define GREYBUS_ID_MATCH_PRODUCT BIT(1)
++#define GREYBUS_ID_MATCH_CLASS BIT(2)
++
++#endif /* __LINUX_GREYBUS_ID_H */
+--- /dev/null
++++ b/drivers/greybus/greybus_manifest.h
+@@ -0,0 +1,177 @@
++/*
++ * Greybus manifest definition
++ *
++ * See "Greybus Application Protocol" document (version 0.1) for
++ * details on these values and structures.
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 and BSD licenses.
++ */
++
++#ifndef __GREYBUS_MANIFEST_H
++#define __GREYBUS_MANIFEST_H
++
++enum greybus_descriptor_type {
++ GREYBUS_TYPE_INVALID = 0x00,
++ GREYBUS_TYPE_INTERFACE = 0x01,
++ GREYBUS_TYPE_STRING = 0x02,
++ GREYBUS_TYPE_BUNDLE = 0x03,
++ GREYBUS_TYPE_CPORT = 0x04,
++};
++
++enum greybus_protocol {
++ GREYBUS_PROTOCOL_CONTROL = 0x00,
++ /* 0x01 is unused */
++ GREYBUS_PROTOCOL_GPIO = 0x02,
++ GREYBUS_PROTOCOL_I2C = 0x03,
++ GREYBUS_PROTOCOL_UART = 0x04,
++ GREYBUS_PROTOCOL_HID = 0x05,
++ GREYBUS_PROTOCOL_USB = 0x06,
++ GREYBUS_PROTOCOL_SDIO = 0x07,
++ GREYBUS_PROTOCOL_POWER_SUPPLY = 0x08,
++ GREYBUS_PROTOCOL_PWM = 0x09,
++ /* 0x0a is unused */
++ GREYBUS_PROTOCOL_SPI = 0x0b,
++ GREYBUS_PROTOCOL_DISPLAY = 0x0c,
++ GREYBUS_PROTOCOL_CAMERA_MGMT = 0x0d,
++ GREYBUS_PROTOCOL_SENSOR = 0x0e,
++ GREYBUS_PROTOCOL_LIGHTS = 0x0f,
++ GREYBUS_PROTOCOL_VIBRATOR = 0x10,
++ GREYBUS_PROTOCOL_LOOPBACK = 0x11,
++ GREYBUS_PROTOCOL_AUDIO_MGMT = 0x12,
++ GREYBUS_PROTOCOL_AUDIO_DATA = 0x13,
++ GREYBUS_PROTOCOL_SVC = 0x14,
++ GREYBUS_PROTOCOL_BOOTROM = 0x15,
++ GREYBUS_PROTOCOL_CAMERA_DATA = 0x16,
++ GREYBUS_PROTOCOL_FW_DOWNLOAD = 0x17,
++ GREYBUS_PROTOCOL_FW_MANAGEMENT = 0x18,
++ GREYBUS_PROTOCOL_AUTHENTICATION = 0x19,
++ GREYBUS_PROTOCOL_LOG = 0x1a,
++ /* ... */
++ GREYBUS_PROTOCOL_RAW = 0xfe,
++ GREYBUS_PROTOCOL_VENDOR = 0xff,
++};
++
++enum greybus_class_type {
++ GREYBUS_CLASS_CONTROL = 0x00,
++ /* 0x01 is unused */
++ /* 0x02 is unused */
++ /* 0x03 is unused */
++ /* 0x04 is unused */
++ GREYBUS_CLASS_HID = 0x05,
++ /* 0x06 is unused */
++ /* 0x07 is unused */
++ GREYBUS_CLASS_POWER_SUPPLY = 0x08,
++ /* 0x09 is unused */
++ GREYBUS_CLASS_BRIDGED_PHY = 0x0a,
++ /* 0x0b is unused */
++ GREYBUS_CLASS_DISPLAY = 0x0c,
++ GREYBUS_CLASS_CAMERA = 0x0d,
++ GREYBUS_CLASS_SENSOR = 0x0e,
++ GREYBUS_CLASS_LIGHTS = 0x0f,
++ GREYBUS_CLASS_VIBRATOR = 0x10,
++ GREYBUS_CLASS_LOOPBACK = 0x11,
++ GREYBUS_CLASS_AUDIO = 0x12,
++ /* 0x13 is unused */
++ /* 0x14 is unused */
++ GREYBUS_CLASS_BOOTROM = 0x15,
++ GREYBUS_CLASS_FW_MANAGEMENT = 0x16,
++ GREYBUS_CLASS_LOG = 0x17,
++ /* ... */
++ GREYBUS_CLASS_RAW = 0xfe,
++ GREYBUS_CLASS_VENDOR = 0xff,
++};
++
++enum {
++ GREYBUS_INTERFACE_FEATURE_TIMESYNC = BIT(0),
++};
++
++/*
++ * The string in a string descriptor is not NUL-terminated. The
++ * size of the descriptor will be rounded up to a multiple of 4
++ * bytes, by padding the string with 0x00 bytes if necessary.
++ */
++struct greybus_descriptor_string {
++ __u8 length;
++ __u8 id;
++ __u8 string[0];
++} __packed;
++
++/*
++ * An interface descriptor describes information about an interface as a whole,
++ * *not* the functions within it.
++ */
++struct greybus_descriptor_interface {
++ __u8 vendor_stringid;
++ __u8 product_stringid;
++ __u8 features;
++ __u8 pad;
++} __packed;
++
++/*
++ * An bundle descriptor defines an identification number and a class for
++ * each bundle.
++ *
++ * @id: Uniquely identifies a bundle within a interface, its sole purpose is to
++ * allow CPort descriptors to specify which bundle they are associated with.
++ * The first bundle will have id 0, second will have 1 and so on.
++ *
++ * The largest CPort id associated with an bundle (defined by a
++ * CPort descriptor in the manifest) is used to determine how to
++ * encode the device id and module number in UniPro packets
++ * that use the bundle.
++ *
++ * @class: It is used by kernel to know the functionality provided by the
++ * bundle and will be matched against drivers functinality while probing greybus
++ * driver. It should contain one of the values defined in
++ * 'enum greybus_class_type'.
++ *
++ */
++struct greybus_descriptor_bundle {
++ __u8 id; /* interface-relative id (0..) */
++ __u8 class;
++ __u8 pad[2];
++} __packed;
++
++/*
++ * A CPort descriptor indicates the id of the bundle within the
++ * module it's associated with, along with the CPort id used to
++ * address the CPort. The protocol id defines the format of messages
++ * exchanged using the CPort.
++ */
++struct greybus_descriptor_cport {
++ __le16 id;
++ __u8 bundle;
++ __u8 protocol_id; /* enum greybus_protocol */
++} __packed;
++
++struct greybus_descriptor_header {
++ __le16 size;
++ __u8 type; /* enum greybus_descriptor_type */
++ __u8 pad;
++} __packed;
++
++struct greybus_descriptor {
++ struct greybus_descriptor_header header;
++ union {
++ struct greybus_descriptor_string string;
++ struct greybus_descriptor_interface interface;
++ struct greybus_descriptor_bundle bundle;
++ struct greybus_descriptor_cport cport;
++ };
++} __packed;
++
++struct greybus_manifest_header {
++ __le16 size;
++ __u8 version_major;
++ __u8 version_minor;
++} __packed;
++
++struct greybus_manifest {
++ struct greybus_manifest_header header;
++ struct greybus_descriptor descriptors[0];
++} __packed;
++
++#endif /* __GREYBUS_MANIFEST_H */
+--- /dev/null
++++ b/drivers/greybus/manifest.c
+@@ -0,0 +1,535 @@
++/*
++ * Greybus manifest parsing
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++
++static const char *get_descriptor_type_string(u8 type)
++{
++ switch(type) {
++ case GREYBUS_TYPE_INVALID:
++ return "invalid";
++ case GREYBUS_TYPE_STRING:
++ return "string";
++ case GREYBUS_TYPE_INTERFACE:
++ return "interface";
++ case GREYBUS_TYPE_CPORT:
++ return "cport";
++ case GREYBUS_TYPE_BUNDLE:
++ return "bundle";
++ default:
++ WARN_ON(1);
++ return "unknown";
++ }
++}
++
++/*
++ * We scan the manifest once to identify where all the descriptors
++ * are. The result is a list of these manifest_desc structures. We
++ * then pick through them for what we're looking for (starting with
++ * the interface descriptor). As each is processed we remove it from
++ * the list. When we're done the list should (probably) be empty.
++ */
++struct manifest_desc {
++ struct list_head links;
++
++ size_t size;
++ void *data;
++ enum greybus_descriptor_type type;
++};
++
++static void release_manifest_descriptor(struct manifest_desc *descriptor)
++{
++ list_del(&descriptor->links);
++ kfree(descriptor);
++}
++
++static void release_manifest_descriptors(struct gb_interface *intf)
++{
++ struct manifest_desc *descriptor;
++ struct manifest_desc *next;
++
++ list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
++ release_manifest_descriptor(descriptor);
++}
++
++static void release_cport_descriptors(struct list_head *head, u8 bundle_id)
++{
++ struct manifest_desc *desc, *tmp;
++ struct greybus_descriptor_cport *desc_cport;
++
++ list_for_each_entry_safe(desc, tmp, head, links) {
++ desc_cport = desc->data;
++
++ if (desc->type != GREYBUS_TYPE_CPORT)
++ continue;
++
++ if (desc_cport->bundle == bundle_id)
++ release_manifest_descriptor(desc);
++ }
++}
++
++static struct manifest_desc *get_next_bundle_desc(struct gb_interface *intf)
++{
++ struct manifest_desc *descriptor;
++ struct manifest_desc *next;
++
++ list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
++ if (descriptor->type == GREYBUS_TYPE_BUNDLE)
++ return descriptor;
++
++ return NULL;
++}
++
++/*
++ * Validate the given descriptor. Its reported size must fit within
++ * the number of bytes remaining, and it must have a recognized
++ * type. Check that the reported size is at least as big as what
++ * we expect to see. (It could be bigger, perhaps for a new version
++ * of the format.)
++ *
++ * Returns the (non-zero) number of bytes consumed by the descriptor,
++ * or a negative errno.
++ */
++static int identify_descriptor(struct gb_interface *intf,
++ struct greybus_descriptor *desc, size_t size)
++{
++ struct greybus_descriptor_header *desc_header = &desc->header;
++ struct manifest_desc *descriptor;
++ size_t desc_size;
++ size_t expected_size;
++
++ if (size < sizeof(*desc_header)) {
++ dev_err(&intf->dev, "manifest too small (%zu < %zu)\n",
++ size, sizeof(*desc_header));
++ return -EINVAL; /* Must at least have header */
++ }
++
++ desc_size = le16_to_cpu(desc_header->size);
++ if (desc_size > size) {
++ dev_err(&intf->dev, "descriptor too big (%zu > %zu)\n",
++ desc_size, size);
++ return -EINVAL;
++ }
++
++ /* Descriptor needs to at least have a header */
++ expected_size = sizeof(*desc_header);
++
++ switch (desc_header->type) {
++ case GREYBUS_TYPE_STRING:
++ expected_size += sizeof(struct greybus_descriptor_string);
++ expected_size += desc->string.length;
++
++ /* String descriptors are padded to 4 byte boundaries */
++ expected_size = ALIGN(expected_size, 4);
++ break;
++ case GREYBUS_TYPE_INTERFACE:
++ expected_size += sizeof(struct greybus_descriptor_interface);
++ break;
++ case GREYBUS_TYPE_BUNDLE:
++ expected_size += sizeof(struct greybus_descriptor_bundle);
++ break;
++ case GREYBUS_TYPE_CPORT:
++ expected_size += sizeof(struct greybus_descriptor_cport);
++ break;
++ case GREYBUS_TYPE_INVALID:
++ default:
++ dev_err(&intf->dev, "invalid descriptor type (%u)\n",
++ desc_header->type);
++ return -EINVAL;
++ }
++
++ if (desc_size < expected_size) {
++ dev_err(&intf->dev, "%s descriptor too small (%zu < %zu)\n",
++ get_descriptor_type_string(desc_header->type),
++ desc_size, expected_size);
++ return -EINVAL;
++ }
++
++ /* Descriptor bigger than what we expect */
++ if (desc_size > expected_size) {
++ dev_warn(&intf->dev, "%s descriptor size mismatch (want %zu got %zu)\n",
++ get_descriptor_type_string(desc_header->type),
++ expected_size, desc_size);
++ }
++
++ descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL);
++ if (!descriptor)
++ return -ENOMEM;
++
++ descriptor->size = desc_size;
++ descriptor->data = (char *)desc + sizeof(*desc_header);
++ descriptor->type = desc_header->type;
++ list_add_tail(&descriptor->links, &intf->manifest_descs);
++
++ /* desc_size is positive and is known to fit in a signed int */
++
++ return desc_size;
++}
++
++/*
++ * Find the string descriptor having the given id, validate it, and
++ * allocate a duplicate copy of it. The duplicate has an extra byte
++ * which guarantees the returned string is NUL-terminated.
++ *
++ * String index 0 is valid (it represents "no string"), and for
++ * that a null pointer is returned.
++ *
++ * Otherwise returns a pointer to a newly-allocated copy of the
++ * descriptor string, or an error-coded pointer on failure.
++ */
++static char *gb_string_get(struct gb_interface *intf, u8 string_id)
++{
++ struct greybus_descriptor_string *desc_string;
++ struct manifest_desc *descriptor;
++ bool found = false;
++ char *string;
++
++ /* A zero string id means no string (but no error) */
++ if (!string_id)
++ return NULL;
++
++ list_for_each_entry(descriptor, &intf->manifest_descs, links) {
++ if (descriptor->type != GREYBUS_TYPE_STRING)
++ continue;
++
++ desc_string = descriptor->data;
++ if (desc_string->id == string_id) {
++ found = true;
++ break;
++ }
++ }
++ if (!found)
++ return ERR_PTR(-ENOENT);
++
++ /* Allocate an extra byte so we can guarantee it's NUL-terminated */
++ string = kmemdup(&desc_string->string, desc_string->length + 1,
++ GFP_KERNEL);
++ if (!string)
++ return ERR_PTR(-ENOMEM);
++ string[desc_string->length] = '\0';
++
++ /* Ok we've used this string, so we're done with it */
++ release_manifest_descriptor(descriptor);
++
++ return string;
++}
++
++/*
++ * Find cport descriptors in the manifest associated with the given
++ * bundle, and set up data structures for the functions that use
++ * them. Returns the number of cports set up for the bundle, or 0
++ * if there is an error.
++ */
++static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
++{
++ struct gb_interface *intf = bundle->intf;
++ struct greybus_descriptor_cport *desc_cport;
++ struct manifest_desc *desc, *next, *tmp;
++ LIST_HEAD(list);
++ u8 bundle_id = bundle->id;
++ u16 cport_id;
++ u32 count = 0;
++ int i;
++
++ /* Set up all cport descriptors associated with this bundle */
++ list_for_each_entry_safe(desc, next, &intf->manifest_descs, links) {
++ if (desc->type != GREYBUS_TYPE_CPORT)
++ continue;
++
++ desc_cport = desc->data;
++ if (desc_cport->bundle != bundle_id)
++ continue;
++
++ cport_id = le16_to_cpu(desc_cport->id);
++ if (cport_id > CPORT_ID_MAX)
++ goto exit;
++
++ /* Nothing else should have its cport_id as control cport id */
++ if (cport_id == GB_CONTROL_CPORT_ID) {
++ dev_err(&bundle->dev, "invalid cport id found (%02u)\n",
++ cport_id);
++ goto exit;
++ }
++
++ /*
++ * Found one, move it to our temporary list after checking for
++ * duplicates.
++ */
++ list_for_each_entry(tmp, &list, links) {
++ desc_cport = tmp->data;
++ if (cport_id == le16_to_cpu(desc_cport->id)) {
++ dev_err(&bundle->dev,
++ "duplicate CPort %u found\n",
++ cport_id);
++ goto exit;
++ }
++ }
++ list_move_tail(&desc->links, &list);
++ count++;
++ }
++
++ if (!count)
++ return 0;
++
++ bundle->cport_desc = kcalloc(count, sizeof(*bundle->cport_desc),
++ GFP_KERNEL);
++ if (!bundle->cport_desc)
++ goto exit;
++
++ bundle->num_cports = count;
++
++ i = 0;
++ list_for_each_entry_safe(desc, next, &list, links) {
++ desc_cport = desc->data;
++ memcpy(&bundle->cport_desc[i++], desc_cport,
++ sizeof(*desc_cport));
++
++ /* Release the cport descriptor */
++ release_manifest_descriptor(desc);
++ }
++
++ return count;
++exit:
++ release_cport_descriptors(&list, bundle_id);
++ /*
++ * Free all cports for this bundle to avoid 'excess descriptors'
++ * warnings.
++ */
++ release_cport_descriptors(&intf->manifest_descs, bundle_id);
++
++ return 0; /* Error; count should also be 0 */
++}
++
++/*
++ * Find bundle descriptors in the manifest and set up their data
++ * structures. Returns the number of bundles set up for the
++ * given interface.
++ */
++static u32 gb_manifest_parse_bundles(struct gb_interface *intf)
++{
++ struct manifest_desc *desc;
++ struct gb_bundle *bundle;
++ struct gb_bundle *bundle_next;
++ u32 count = 0;
++ u8 bundle_id;
++ u8 class;
++
++ while ((desc = get_next_bundle_desc(intf))) {
++ struct greybus_descriptor_bundle *desc_bundle;
++
++ /* Found one. Set up its bundle structure*/
++ desc_bundle = desc->data;
++ bundle_id = desc_bundle->id;
++ class = desc_bundle->class;
++
++ /* Done with this bundle descriptor */
++ release_manifest_descriptor(desc);
++
++ /* Ignore any legacy control bundles */
++ if (bundle_id == GB_CONTROL_BUNDLE_ID) {
++ dev_dbg(&intf->dev, "%s - ignoring control bundle\n",
++ __func__);
++ release_cport_descriptors(&intf->manifest_descs,
++ bundle_id);
++ continue;
++ }
++
++ /* Nothing else should have its class set to control class */
++ if (class == GREYBUS_CLASS_CONTROL) {
++ dev_err(&intf->dev,
++ "bundle %u cannot use control class\n",
++ bundle_id);
++ goto cleanup;
++ }
++
++ bundle = gb_bundle_create(intf, bundle_id, class);
++ if (!bundle)
++ goto cleanup;
++
++ /*
++ * Now go set up this bundle's functions and cports.
++ *
++ * A 'bundle' represents a device in greybus. It may require
++ * multiple cports for its functioning. If we fail to setup any
++ * cport of a bundle, we better reject the complete bundle as
++ * the device may not be able to function properly then.
++ *
++ * But, failing to setup a cport of bundle X doesn't mean that
++ * the device corresponding to bundle Y will not work properly.
++ * Bundles should be treated as separate independent devices.
++ *
++ * While parsing manifest for an interface, treat bundles as
++ * separate entities and don't reject entire interface and its
++ * bundles on failing to initialize a cport. But make sure the
++ * bundle which needs the cport, gets destroyed properly.
++ */
++ if (!gb_manifest_parse_cports(bundle)) {
++ gb_bundle_destroy(bundle);
++ continue;
++ }
++
++ count++;
++ }
++
++ return count;
++cleanup:
++ /* An error occurred; undo any changes we've made */
++ list_for_each_entry_safe(bundle, bundle_next, &intf->bundles, links) {
++ gb_bundle_destroy(bundle);
++ count--;
++ }
++ return 0; /* Error; count should also be 0 */
++}
++
++static bool gb_manifest_parse_interface(struct gb_interface *intf,
++ struct manifest_desc *interface_desc)
++{
++ struct greybus_descriptor_interface *desc_intf = interface_desc->data;
++ struct gb_control *control = intf->control;
++ char *str;
++
++ /* Handle the strings first--they can fail */
++ str = gb_string_get(intf, desc_intf->vendor_stringid);
++ if (IS_ERR(str))
++ return false;
++ control->vendor_string = str;
++
++ str = gb_string_get(intf, desc_intf->product_stringid);
++ if (IS_ERR(str))
++ goto out_free_vendor_string;
++ control->product_string = str;
++
++ /* Assign feature flags communicated via manifest */
++ intf->features = desc_intf->features;
++
++ /* Release the interface descriptor, now that we're done with it */
++ release_manifest_descriptor(interface_desc);
++
++ /* An interface must have at least one bundle descriptor */
++ if (!gb_manifest_parse_bundles(intf)) {
++ dev_err(&intf->dev, "manifest bundle descriptors not valid\n");
++ goto out_err;
++ }
++
++ return true;
++out_err:
++ kfree(control->product_string);
++ control->product_string = NULL;
++out_free_vendor_string:
++ kfree(control->vendor_string);
++ control->vendor_string = NULL;
++
++ return false;
++}
++
++/*
++ * Parse a buffer containing an interface manifest.
++ *
++ * If we find anything wrong with the content/format of the buffer
++ * we reject it.
++ *
++ * The first requirement is that the manifest's version is
++ * one we can parse.
++ *
++ * We make an initial pass through the buffer and identify all of
++ * the descriptors it contains, keeping track for each its type
++ * and the location size of its data in the buffer.
++ *
++ * Next we scan the descriptors, looking for an interface descriptor;
++ * there must be exactly one of those. When found, we record the
++ * information it contains, and then remove that descriptor (and any
++ * string descriptors it refers to) from further consideration.
++ *
++ * After that we look for the interface's bundles--there must be at
++ * least one of those.
++ *
++ * Returns true if parsing was successful, false otherwise.
++ */
++bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size)
++{
++ struct greybus_manifest *manifest;
++ struct greybus_manifest_header *header;
++ struct greybus_descriptor *desc;
++ struct manifest_desc *descriptor;
++ struct manifest_desc *interface_desc = NULL;
++ u16 manifest_size;
++ u32 found = 0;
++ bool result;
++
++ /* Manifest descriptor list should be empty here */
++ if (WARN_ON(!list_empty(&intf->manifest_descs)))
++ return false;
++
++ /* we have to have at _least_ the manifest header */
++ if (size < sizeof(*header)) {
++ dev_err(&intf->dev, "short manifest (%zu < %zu)\n",
++ size, sizeof(*header));
++ return false;
++ }
++
++ /* Make sure the size is right */
++ manifest = data;
++ header = &manifest->header;
++ manifest_size = le16_to_cpu(header->size);
++ if (manifest_size != size) {
++ dev_err(&intf->dev, "manifest size mismatch (%zu != %u)\n",
++ size, manifest_size);
++ return false;
++ }
++
++ /* Validate major/minor number */
++ if (header->version_major > GREYBUS_VERSION_MAJOR) {
++ dev_err(&intf->dev, "manifest version too new (%u.%u > %u.%u)\n",
++ header->version_major, header->version_minor,
++ GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR);
++ return false;
++ }
++
++ /* OK, find all the descriptors */
++ desc = manifest->descriptors;
++ size -= sizeof(*header);
++ while (size) {
++ int desc_size;
++
++ desc_size = identify_descriptor(intf, desc, size);
++ if (desc_size < 0) {
++ result = false;
++ goto out;
++ }
++ desc = (struct greybus_descriptor *)((char *)desc + desc_size);
++ size -= desc_size;
++ }
++
++ /* There must be a single interface descriptor */
++ list_for_each_entry(descriptor, &intf->manifest_descs, links) {
++ if (descriptor->type == GREYBUS_TYPE_INTERFACE)
++ if (!found++)
++ interface_desc = descriptor;
++ }
++ if (found != 1) {
++ dev_err(&intf->dev, "manifest must have 1 interface descriptor (%u found)\n",
++ found);
++ result = false;
++ goto out;
++ }
++
++ /* Parse the manifest, starting with the interface descriptor */
++ result = gb_manifest_parse_interface(intf, interface_desc);
++
++ /*
++ * We really should have no remaining descriptors, but we
++ * don't know what newer format manifests might leave.
++ */
++ if (result && !list_empty(&intf->manifest_descs))
++ dev_info(&intf->dev, "excess descriptors in interface manifest\n");
++out:
++ release_manifest_descriptors(intf);
++
++ return result;
++}
+--- /dev/null
++++ b/drivers/greybus/manifest.h
+@@ -0,0 +1,16 @@
++/*
++ * Greybus manifest parsing
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __MANIFEST_H
++#define __MANIFEST_H
++
++struct gb_interface;
++bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size);
++
++#endif /* __MANIFEST_H */
+--- /dev/null
++++ b/drivers/greybus/module.c
+@@ -0,0 +1,238 @@
++/*
++ * Greybus Module code
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++
++static ssize_t eject_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct gb_module *module = to_gb_module(dev);
++ struct gb_interface *intf;
++ size_t i;
++ long val;
++ int ret;
++
++ ret = kstrtol(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ if (!val)
++ return len;
++
++ for (i = 0; i < module->num_interfaces; ++i) {
++ intf = module->interfaces[i];
++
++ mutex_lock(&intf->mutex);
++ /* Set flag to prevent concurrent activation. */
++ intf->ejected = true;
++ gb_interface_disable(intf);
++ gb_interface_deactivate(intf);
++ mutex_unlock(&intf->mutex);
++ }
++
++ /* Tell the SVC to eject the primary interface. */
++ ret = gb_svc_intf_eject(module->hd->svc, module->module_id);
++ if (ret)
++ return ret;
++
++ return len;
++}
++static DEVICE_ATTR_WO(eject);
++
++static ssize_t module_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_module *module = to_gb_module(dev);
++
++ return sprintf(buf, "%u\n", module->module_id);
++}
++static DEVICE_ATTR_RO(module_id);
++
++static ssize_t num_interfaces_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_module *module = to_gb_module(dev);
++
++ return sprintf(buf, "%zu\n", module->num_interfaces);
++}
++static DEVICE_ATTR_RO(num_interfaces);
++
++static struct attribute *module_attrs[] = {
++ &dev_attr_eject.attr,
++ &dev_attr_module_id.attr,
++ &dev_attr_num_interfaces.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(module);
++
++static void gb_module_release(struct device *dev)
++{
++ struct gb_module *module = to_gb_module(dev);
++
++ trace_gb_module_release(module);
++
++ kfree(module);
++}
++
++struct device_type greybus_module_type = {
++ .name = "greybus_module",
++ .release = gb_module_release,
++};
++
++struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id,
++ size_t num_interfaces)
++{
++ struct gb_interface *intf;
++ struct gb_module *module;
++ int i;
++
++ module = kzalloc(sizeof(*module) + num_interfaces * sizeof(intf),
++ GFP_KERNEL);
++ if (!module)
++ return NULL;
++
++ module->hd = hd;
++ module->module_id = module_id;
++ module->num_interfaces = num_interfaces;
++
++ module->dev.parent = &hd->dev;
++ module->dev.bus = &greybus_bus_type;
++ module->dev.type = &greybus_module_type;
++ module->dev.groups = module_groups;
++ module->dev.dma_mask = hd->dev.dma_mask;
++ device_initialize(&module->dev);
++ dev_set_name(&module->dev, "%d-%u", hd->bus_id, module_id);
++
++ trace_gb_module_create(module);
++
++ for (i = 0; i < num_interfaces; ++i) {
++ intf = gb_interface_create(module, module_id + i);
++ if (!intf) {
++ dev_err(&module->dev, "failed to create interface %u\n",
++ module_id + i);
++ goto err_put_interfaces;
++ }
++ module->interfaces[i] = intf;
++ }
++
++ return module;
++
++err_put_interfaces:
++ for (--i; i > 0; --i)
++ gb_interface_put(module->interfaces[i]);
++
++ put_device(&module->dev);
++
++ return NULL;
++}
++
++/*
++ * Register and enable an interface after first attempting to activate it.
++ */
++static void gb_module_register_interface(struct gb_interface *intf)
++{
++ struct gb_module *module = intf->module;
++ u8 intf_id = intf->interface_id;
++ int ret;
++
++ mutex_lock(&intf->mutex);
++
++ ret = gb_interface_activate(intf);
++ if (ret) {
++ if (intf->type != GB_INTERFACE_TYPE_DUMMY) {
++ dev_err(&module->dev,
++ "failed to activate interface %u: %d\n",
++ intf_id, ret);
++ }
++
++ gb_interface_add(intf);
++ goto err_unlock;
++ }
++
++ ret = gb_interface_add(intf);
++ if (ret)
++ goto err_interface_deactivate;
++
++ ret = gb_interface_enable(intf);
++ if (ret) {
++ dev_err(&module->dev, "failed to enable interface %u: %d\n",
++ intf_id, ret);
++ goto err_interface_deactivate;
++ }
++
++ mutex_unlock(&intf->mutex);
++
++ return;
++
++err_interface_deactivate:
++ gb_interface_deactivate(intf);
++err_unlock:
++ mutex_unlock(&intf->mutex);
++}
++
++static void gb_module_deregister_interface(struct gb_interface *intf)
++{
++ /* Mark as disconnected to prevent I/O during disable. */
++ if (intf->module->disconnected)
++ intf->disconnected = true;
++
++ mutex_lock(&intf->mutex);
++ intf->removed = true;
++ gb_interface_disable(intf);
++ gb_interface_deactivate(intf);
++ mutex_unlock(&intf->mutex);
++
++ gb_interface_del(intf);
++}
++
++/* Register a module and its interfaces. */
++int gb_module_add(struct gb_module *module)
++{
++ size_t i;
++ int ret;
++
++ ret = device_add(&module->dev);
++ if (ret) {
++ dev_err(&module->dev, "failed to register module: %d\n", ret);
++ return ret;
++ }
++
++ trace_gb_module_add(module);
++
++ for (i = 0; i < module->num_interfaces; ++i)
++ gb_module_register_interface(module->interfaces[i]);
++
++ return 0;
++}
++
++/* Deregister a module and its interfaces. */
++void gb_module_del(struct gb_module *module)
++{
++ size_t i;
++
++ for (i = 0; i < module->num_interfaces; ++i)
++ gb_module_deregister_interface(module->interfaces[i]);
++
++ trace_gb_module_del(module);
++
++ device_del(&module->dev);
++}
++
++void gb_module_put(struct gb_module *module)
++{
++ size_t i;
++
++ for (i = 0; i < module->num_interfaces; ++i)
++ gb_interface_put(module->interfaces[i]);
++
++ put_device(&module->dev);
++}
+--- /dev/null
++++ b/drivers/greybus/module.h
+@@ -0,0 +1,34 @@
++/*
++ * Greybus Module code
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __MODULE_H
++#define __MODULE_H
++
++struct gb_module {
++ struct device dev;
++ struct gb_host_device *hd;
++
++ struct list_head hd_node;
++
++ u8 module_id;
++ size_t num_interfaces;
++
++ bool disconnected;
++
++ struct gb_interface *interfaces[0];
++};
++#define to_gb_module(d) container_of(d, struct gb_module, dev)
++
++struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id,
++ size_t num_interfaces);
++int gb_module_add(struct gb_module *module);
++void gb_module_del(struct gb_module *module);
++void gb_module_put(struct gb_module *module);
++
++#endif /* __MODULE_H */
diff --git a/greybus_docs.patch b/greybus_docs.patch
new file mode 100644
index 00000000000000..63ea77e7f598f1
--- /dev/null
+++ b/greybus_docs.patch
@@ -0,0 +1,282 @@
+---
+ Documentation/ABI/testing/sysfs-bus-greybus | 275 ++++++++++++++++++++++++++++
+ 1 file changed, 275 insertions(+)
+
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-bus-greybus
+@@ -0,0 +1,275 @@
++What: /sys/bus/greybus/devices/greybusN
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The "root" greybus device for the Greybus device tree, or bus,
++ where N is a dynamically assigned 1-based id.
++
++What: /sys/bus/greybus/devices/greybusN/bus_id
++Date: April 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The ID of the "root" greybus device, or bus.
++
++What: /sys/bus/greybus/devices/N-M
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ A Module M on the bus N, where M is the 1-byte interface
++ ID of the module's primary interface.
++
++What: /sys/bus/greybus/devices/N-M/eject
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Writing a non-zero argument to this attibute disables the
++ module's interfaces before physically ejecting it.
++
++What: /sys/bus/greybus/devices/N-M/module_id
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The ID of a Greybus module, corresponding to the ID of its
++ primary interface.
++
++What: /sys/bus/greybus/devices/N-M/num_interfaces
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The number of interfaces of a module.
++
++What: /sys/bus/greybus/devices/N-M.I
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ An Interface I on the bus N and module N-M, where I is the
++ 1-byte interface ID.
++
++What: /sys/bus/greybus/devices/N-M.I/current_now
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Current measurement of the interface in microamps (uA)
++
++What: /sys/bus/greybus/devices/N-M.I/ddbl1_manufacturer_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Unipro Device Descriptor Block Level 1 manufacturer ID for the
++ greybus Interface.
++
++What: /sys/bus/greybus/devices/N-M.I/ddbl1_product_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Unipro Device Descriptor Block Level 1 product ID for the
++ greybus Interface.
++
++What: /sys/bus/greybus/devices/N-M.I/interface_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The ID of a Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I/interface_type
++Date: June 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The type of a Greybus interface; "dummy", "unipro", "greybus",
++ or "unknown".
++
++What: /sys/bus/greybus/devices/N-M.I/power_now
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Power measurement of the interface in microwatts (uW)
++
++What: /sys/bus/greybus/devices/N-M.I/power_state
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ This file reflects the power state of a Greybus interface. If
++ the value read from it is "on", then power is currently
++ supplied to the interface. Otherwise it will read "off" and
++ power is currently not supplied to the interface.
++
++ If the value read is "off", then writing "on" (or '1', 'y',
++ 'Y') to this file will enable power to the interface and an
++ attempt to boot and possibly enumerate it will be made. Note
++ that on errors, the interface will again be powered down.
++
++ If the value read is "on", then writing "off" (or '0', 'n',
++ 'N') to this file will power down the interface.
++
++What: /sys/bus/greybus/devices/N-M.I/product_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Product ID of a Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I/serial_number
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Serial Number of the Greybus interface, represented by a 64 bit
++ hexadecimal number.
++
++What: /sys/bus/greybus/devices/N-M.I/vendor_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Vendor ID of a Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I/voltage_now
++Date: March 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Voltage measurement of the interface in microvolts (uV)
++
++What: /sys/bus/greybus/devices/N-M.I.ctrl
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Abstract control device for interface I that represents the
++ current mode of an enumerated Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I.ctrl/product_string
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Product ID string of a Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I.ctrl/vendor_string
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Vendor ID string of a Greybus interface.
++
++What: /sys/bus/greybus/devices/N-M.I.B
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ A bundle B on the Interface I, B is replaced by a 1-byte
++ number representing the bundle.
++
++What: /sys/bus/greybus/devices/N-M.I.B/bundle_class
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The greybus class of the bundle B.
++
++What: /sys/bus/greybus/devices/N-M.I.B/bundle_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The interface-unique id of the bundle B.
++
++What: /sys/bus/greybus/devices/N-M.I.B/gpbX
++Date: April 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The General Purpose Bridged PHY device of the bundle B,
++ where X is a dynamically assigned 0-based id.
++
++What: /sys/bus/greybus/devices/N-M.I.B/state
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ A bundle has a state that is managed by the userspace
++ Endo process. This file allows that Endo to signal
++ other Android HALs that the state of the bundle has
++ changed to a specific value. When written to, any
++ process watching the file will be woken up, and the new
++ value can be read. It's a "poor-man's IPC", yes, but
++ simplifies the Android userspace code immensely.
++
++What: /sys/bus/greybus/devices/N-svc
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The singleton SVC device of bus N.
++
++What: /sys/bus/greybus/devices/N-svc/ap_intf_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The AP interface ID, a 1-byte non-zero integer which
++ defines the position of the AP module on the frame.
++ The interface positions are defined in the GMP
++ Module Developer Kit.
++
++What: /sys/bus/greybus/devices/N-svc/endo_id
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The Endo ID, which is a 2-byte hexadecimal value
++ defined by the Endo layout scheme, documented in
++ the GMP Module Developer Kit.
++
++What: /sys/bus/greybus/devices/N-svc/intf_eject
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ Write the number of the interface that you wish to
++ forcibly eject from the system.
++
++What: /sys/bus/greybus/devices/N-svc/version
++Date: October 2015
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ The version number of the firmware in the SVC device.
++
++What: /sys/bus/greybus/devices/N-svc/watchdog
++Date: October 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ If the SVC watchdog is enabled or not. Writing 0 to this
++ file will disable the watchdog, writing 1 will enable it.
++
++What: /sys/bus/greybus/devices/N-svc/watchdog_action
++Date: July 2016
++KernelVersion: 4.9
++Contact: Greg Kroah-Hartman <greg@kroah.com>
++Description:
++ This attribute indicates the action to be performed upon SVC
++ watchdog bite.
++
++ The action can be one of the "reset" or "panic". Writing either
++ one of the "reset" or "panic" will change the behavior of SVC
++ watchdog bite. Default value is "reset".
++
++ "reset" means the UniPro subsystem is to be reset.
++
++ "panic" means SVC watchdog bite will cause kernel to panic.
diff --git a/greybus_es2.patch b/greybus_es2.patch
new file mode 100644
index 00000000000000..348f530ba46d6b
--- /dev/null
+++ b/greybus_es2.patch
@@ -0,0 +1,1604 @@
+---
+ drivers/greybus/es2.c | 1597 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1597 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/es2.c
+@@ -0,0 +1,1597 @@
++/*
++ * Greybus "AP" USB driver for "ES2" controller chips
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/kthread.h>
++#include <linux/sizes.h>
++#include <linux/usb.h>
++#include <linux/kfifo.h>
++#include <linux/debugfs.h>
++#include <linux/list.h>
++#include <asm/unaligned.h>
++
++#include "arpc.h"
++#include "greybus.h"
++#include "greybus_trace.h"
++#include "connection.h"
++
++
++/* Default timeout for USB vendor requests. */
++#define ES2_USB_CTRL_TIMEOUT 500
++
++/* Default timeout for ARPC CPort requests */
++#define ES2_ARPC_CPORT_TIMEOUT 500
++
++/* Fixed CPort numbers */
++#define ES2_CPORT_CDSI0 16
++#define ES2_CPORT_CDSI1 17
++
++/* Memory sizes for the buffers sent to/from the ES2 controller */
++#define ES2_GBUF_MSG_SIZE_MAX 2048
++
++/* Memory sizes for the ARPC buffers */
++#define ARPC_OUT_SIZE_MAX U16_MAX
++#define ARPC_IN_SIZE_MAX 128
++
++static const struct usb_device_id id_table[] = {
++ { USB_DEVICE(0x18d1, 0x1eaf) },
++ { },
++};
++MODULE_DEVICE_TABLE(usb, id_table);
++
++#define APB1_LOG_SIZE SZ_16K
++
++/*
++ * Number of CPort IN urbs in flight at any point in time.
++ * Adjust if we are having stalls in the USB buffer due to not enough urbs in
++ * flight.
++ */
++#define NUM_CPORT_IN_URB 4
++
++/* Number of CPort OUT urbs in flight at any point in time.
++ * Adjust if we get messages saying we are out of urbs in the system log.
++ */
++#define NUM_CPORT_OUT_URB 8
++
++/*
++ * Number of ARPC in urbs in flight at any point in time.
++ */
++#define NUM_ARPC_IN_URB 2
++
++/*
++ * @endpoint: bulk in endpoint for CPort data
++ * @urb: array of urbs for the CPort in messages
++ * @buffer: array of buffers for the @cport_in_urb urbs
++ */
++struct es2_cport_in {
++ __u8 endpoint;
++ struct urb *urb[NUM_CPORT_IN_URB];
++ u8 *buffer[NUM_CPORT_IN_URB];
++};
++
++/**
++ * es2_ap_dev - ES2 USB Bridge to AP structure
++ * @usb_dev: pointer to the USB device we are.
++ * @usb_intf: pointer to the USB interface we are bound to.
++ * @hd: pointer to our gb_host_device structure
++
++ * @cport_in: endpoint, urbs and buffer for cport in messages
++ * @cport_out_endpoint: endpoint for for cport out messages
++ * @cport_out_urb: array of urbs for the CPort out messages
++ * @cport_out_urb_busy: array of flags to see if the @cport_out_urb is busy or
++ * not.
++ * @cport_out_urb_cancelled: array of flags indicating whether the
++ * corresponding @cport_out_urb is being cancelled
++ * @cport_out_urb_lock: locks the @cport_out_urb_busy "list"
++ *
++ * @apb_log_task: task pointer for logging thread
++ * @apb_log_dentry: file system entry for the log file interface
++ * @apb_log_enable_dentry: file system entry for enabling logging
++ * @apb_log_fifo: kernel FIFO to carry logged data
++ * @arpc_urb: array of urbs for the ARPC in messages
++ * @arpc_buffer: array of buffers for the @arpc_urb urbs
++ * @arpc_endpoint_in: bulk in endpoint for APBridgeA RPC
++ * @arpc_id_cycle: gives an unique id to ARPC
++ * @arpc_lock: locks ARPC list
++ * @arpcs: list of in progress ARPCs
++ */
++struct es2_ap_dev {
++ struct usb_device *usb_dev;
++ struct usb_interface *usb_intf;
++ struct gb_host_device *hd;
++
++ struct es2_cport_in cport_in;
++ __u8 cport_out_endpoint;
++ struct urb *cport_out_urb[NUM_CPORT_OUT_URB];
++ bool cport_out_urb_busy[NUM_CPORT_OUT_URB];
++ bool cport_out_urb_cancelled[NUM_CPORT_OUT_URB];
++ spinlock_t cport_out_urb_lock;
++
++ bool cdsi1_in_use;
++
++ struct task_struct *apb_log_task;
++ struct dentry *apb_log_dentry;
++ struct dentry *apb_log_enable_dentry;
++ DECLARE_KFIFO(apb_log_fifo, char, APB1_LOG_SIZE);
++
++ __u8 arpc_endpoint_in;
++ struct urb *arpc_urb[NUM_ARPC_IN_URB];
++ u8 *arpc_buffer[NUM_ARPC_IN_URB];
++
++ int arpc_id_cycle;
++ spinlock_t arpc_lock;
++ struct list_head arpcs;
++};
++
++/**
++ * timesync_enable_request - Enable timesync in an APBridge
++ * @count: number of TimeSync Pulses to expect
++ * @frame_time: the initial FrameTime at the first TimeSync Pulse
++ * @strobe_delay: the expected delay in microseconds between each TimeSync Pulse
++ * @refclk: The AP mandated reference clock to run FrameTime at
++ */
++struct timesync_enable_request {
++ __u8 count;
++ __le64 frame_time;
++ __le32 strobe_delay;
++ __le32 refclk;
++} __packed;
++
++/**
++ * timesync_authoritative_request - Transmit authoritative FrameTime to APBridge
++ * @frame_time: An array of authoritative FrameTimes provided by the SVC
++ * and relayed to the APBridge by the AP
++ */
++struct timesync_authoritative_request {
++ __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
++} __packed;
++
++struct arpc {
++ struct list_head list;
++ struct arpc_request_message *req;
++ struct arpc_response_message *resp;
++ struct completion response_received;
++ bool active;
++};
++
++static inline struct es2_ap_dev *hd_to_es2(struct gb_host_device *hd)
++{
++ return (struct es2_ap_dev *)&hd->hd_priv;
++}
++
++static void cport_out_callback(struct urb *urb);
++static void usb_log_enable(struct es2_ap_dev *es2);
++static void usb_log_disable(struct es2_ap_dev *es2);
++static int arpc_sync(struct es2_ap_dev *es2, u8 type, void *payload,
++ size_t size, int *result, unsigned int timeout);
++
++static int output_sync(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
++{
++ struct usb_device *udev = es2->usb_dev;
++ u8 *data;
++ int retval;
++
++ data = kmalloc(size, GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++ memcpy(data, req, size);
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ cmd,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE,
++ 0, 0, data, size, ES2_USB_CTRL_TIMEOUT);
++ if (retval < 0)
++ dev_err(&udev->dev, "%s: return error %d\n", __func__, retval);
++ else
++ retval = 0;
++
++ kfree(data);
++ return retval;
++}
++
++static void ap_urb_complete(struct urb *urb)
++{
++ struct usb_ctrlrequest *dr = urb->context;
++
++ kfree(dr);
++ usb_free_urb(urb);
++}
++
++static int output_async(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
++{
++ struct usb_device *udev = es2->usb_dev;
++ struct urb *urb;
++ struct usb_ctrlrequest *dr;
++ u8 *buf;
++ int retval;
++
++ urb = usb_alloc_urb(0, GFP_ATOMIC);
++ if (!urb)
++ return -ENOMEM;
++
++ dr = kmalloc(sizeof(*dr) + size, GFP_ATOMIC);
++ if (!dr) {
++ usb_free_urb(urb);
++ return -ENOMEM;
++ }
++
++ buf = (u8 *)dr + sizeof(*dr);
++ memcpy(buf, req, size);
++
++ dr->bRequest = cmd;
++ dr->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
++ dr->wValue = 0;
++ dr->wIndex = 0;
++ dr->wLength = cpu_to_le16(size);
++
++ usb_fill_control_urb(urb, udev, usb_sndctrlpipe(udev, 0),
++ (unsigned char *)dr, buf, size,
++ ap_urb_complete, dr);
++ retval = usb_submit_urb(urb, GFP_ATOMIC);
++ if (retval) {
++ usb_free_urb(urb);
++ kfree(dr);
++ }
++ return retval;
++}
++
++static int output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
++ bool async)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++
++ if (async)
++ return output_async(es2, req, size, cmd);
++
++ return output_sync(es2, req, size, cmd);
++}
++
++static int es2_cport_in_enable(struct es2_ap_dev *es2,
++ struct es2_cport_in *cport_in)
++{
++ struct urb *urb;
++ int ret;
++ int i;
++
++ for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
++ urb = cport_in->urb[i];
++
++ ret = usb_submit_urb(urb, GFP_KERNEL);
++ if (ret) {
++ dev_err(&es2->usb_dev->dev,
++ "failed to submit in-urb: %d\n", ret);
++ goto err_kill_urbs;
++ }
++ }
++
++ return 0;
++
++err_kill_urbs:
++ for (--i; i >= 0; --i) {
++ urb = cport_in->urb[i];
++ usb_kill_urb(urb);
++ }
++
++ return ret;
++}
++
++static void es2_cport_in_disable(struct es2_ap_dev *es2,
++ struct es2_cport_in *cport_in)
++{
++ struct urb *urb;
++ int i;
++
++ for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
++ urb = cport_in->urb[i];
++ usb_kill_urb(urb);
++ }
++}
++
++static int es2_arpc_in_enable(struct es2_ap_dev *es2)
++{
++ struct urb *urb;
++ int ret;
++ int i;
++
++ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
++ urb = es2->arpc_urb[i];
++
++ ret = usb_submit_urb(urb, GFP_KERNEL);
++ if (ret) {
++ dev_err(&es2->usb_dev->dev,
++ "failed to submit arpc in-urb: %d\n", ret);
++ goto err_kill_urbs;
++ }
++ }
++
++ return 0;
++
++err_kill_urbs:
++ for (--i; i >= 0; --i) {
++ urb = es2->arpc_urb[i];
++ usb_kill_urb(urb);
++ }
++
++ return ret;
++}
++
++static void es2_arpc_in_disable(struct es2_ap_dev *es2)
++{
++ struct urb *urb;
++ int i;
++
++ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
++ urb = es2->arpc_urb[i];
++ usb_kill_urb(urb);
++ }
++}
++
++static struct urb *next_free_urb(struct es2_ap_dev *es2, gfp_t gfp_mask)
++{
++ struct urb *urb = NULL;
++ unsigned long flags;
++ int i;
++
++ spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
++
++ /* Look in our pool of allocated urbs first, as that's the "fastest" */
++ for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
++ if (es2->cport_out_urb_busy[i] == false &&
++ es2->cport_out_urb_cancelled[i] == false) {
++ es2->cport_out_urb_busy[i] = true;
++ urb = es2->cport_out_urb[i];
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
++ if (urb)
++ return urb;
++
++ /*
++ * Crap, pool is empty, complain to the syslog and go allocate one
++ * dynamically as we have to succeed.
++ */
++ dev_dbg(&es2->usb_dev->dev,
++ "No free CPort OUT urbs, having to dynamically allocate one!\n");
++ return usb_alloc_urb(0, gfp_mask);
++}
++
++static void free_urb(struct es2_ap_dev *es2, struct urb *urb)
++{
++ unsigned long flags;
++ int i;
++ /*
++ * See if this was an urb in our pool, if so mark it "free", otherwise
++ * we need to free it ourselves.
++ */
++ spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
++ for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
++ if (urb == es2->cport_out_urb[i]) {
++ es2->cport_out_urb_busy[i] = false;
++ urb = NULL;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
++
++ /* If urb is not NULL, then we need to free this urb */
++ usb_free_urb(urb);
++}
++
++/*
++ * We (ab)use the operation-message header pad bytes to transfer the
++ * cport id in order to minimise overhead.
++ */
++static void
++gb_message_cport_pack(struct gb_operation_msg_hdr *header, u16 cport_id)
++{
++ header->pad[0] = cport_id;
++}
++
++/* Clear the pad bytes used for the CPort id */
++static void gb_message_cport_clear(struct gb_operation_msg_hdr *header)
++{
++ header->pad[0] = 0;
++}
++
++/* Extract the CPort id packed into the header, and clear it */
++static u16 gb_message_cport_unpack(struct gb_operation_msg_hdr *header)
++{
++ u16 cport_id = header->pad[0];
++
++ gb_message_cport_clear(header);
++
++ return cport_id;
++}
++
++/*
++ * Returns zero if the message was successfully queued, or a negative errno
++ * otherwise.
++ */
++static int message_send(struct gb_host_device *hd, u16 cport_id,
++ struct gb_message *message, gfp_t gfp_mask)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++ size_t buffer_size;
++ int retval;
++ struct urb *urb;
++ unsigned long flags;
++
++ /*
++ * The data actually transferred will include an indication
++ * of where the data should be sent. Do one last check of
++ * the target CPort id before filling it in.
++ */
++ if (!cport_id_valid(hd, cport_id)) {
++ dev_err(&udev->dev, "invalid cport %u\n", cport_id);
++ return -EINVAL;
++ }
++
++ /* Find a free urb */
++ urb = next_free_urb(es2, gfp_mask);
++ if (!urb)
++ return -ENOMEM;
++
++ spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
++ message->hcpriv = urb;
++ spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
++
++ /* Pack the cport id into the message header */
++ gb_message_cport_pack(message->header, cport_id);
++
++ buffer_size = sizeof(*message->header) + message->payload_size;
++
++ usb_fill_bulk_urb(urb, udev,
++ usb_sndbulkpipe(udev,
++ es2->cport_out_endpoint),
++ message->buffer, buffer_size,
++ cport_out_callback, message);
++ urb->transfer_flags |= URB_ZERO_PACKET;
++
++ trace_gb_message_submit(message);
++
++ retval = usb_submit_urb(urb, gfp_mask);
++ if (retval) {
++ dev_err(&udev->dev, "failed to submit out-urb: %d\n", retval);
++
++ spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
++ message->hcpriv = NULL;
++ spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
++
++ free_urb(es2, urb);
++ gb_message_cport_clear(message->header);
++
++ return retval;
++ }
++
++ return 0;
++}
++
++/*
++ * Can not be called in atomic context.
++ */
++static void message_cancel(struct gb_message *message)
++{
++ struct gb_host_device *hd = message->operation->connection->hd;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct urb *urb;
++ int i;
++
++ might_sleep();
++
++ spin_lock_irq(&es2->cport_out_urb_lock);
++ urb = message->hcpriv;
++
++ /* Prevent dynamically allocated urb from being deallocated. */
++ usb_get_urb(urb);
++
++ /* Prevent pre-allocated urb from being reused. */
++ for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
++ if (urb == es2->cport_out_urb[i]) {
++ es2->cport_out_urb_cancelled[i] = true;
++ break;
++ }
++ }
++ spin_unlock_irq(&es2->cport_out_urb_lock);
++
++ usb_kill_urb(urb);
++
++ if (i < NUM_CPORT_OUT_URB) {
++ spin_lock_irq(&es2->cport_out_urb_lock);
++ es2->cport_out_urb_cancelled[i] = false;
++ spin_unlock_irq(&es2->cport_out_urb_lock);
++ }
++
++ usb_free_urb(urb);
++}
++
++static int es2_cport_allocate(struct gb_host_device *hd, int cport_id,
++ unsigned long flags)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct ida *id_map = &hd->cport_id_map;
++ int ida_start, ida_end;
++
++ switch (cport_id) {
++ case ES2_CPORT_CDSI0:
++ case ES2_CPORT_CDSI1:
++ dev_err(&hd->dev, "cport %d not available\n", cport_id);
++ return -EBUSY;
++ }
++
++ if (flags & GB_CONNECTION_FLAG_OFFLOADED &&
++ flags & GB_CONNECTION_FLAG_CDSI1) {
++ if (es2->cdsi1_in_use) {
++ dev_err(&hd->dev, "CDSI1 already in use\n");
++ return -EBUSY;
++ }
++
++ es2->cdsi1_in_use = true;
++
++ return ES2_CPORT_CDSI1;
++ }
++
++ if (cport_id < 0) {
++ ida_start = 0;
++ ida_end = hd->num_cports;
++ } else if (cport_id < hd->num_cports) {
++ ida_start = cport_id;
++ ida_end = cport_id + 1;
++ } else {
++ dev_err(&hd->dev, "cport %d not available\n", cport_id);
++ return -EINVAL;
++ }
++
++ return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
++}
++
++static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++
++ switch (cport_id) {
++ case ES2_CPORT_CDSI1:
++ es2->cdsi1_in_use = false;
++ return;
++ }
++
++ ida_simple_remove(&hd->cport_id_map, cport_id);
++}
++
++static int cport_enable(struct gb_host_device *hd, u16 cport_id,
++ unsigned long flags)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++ struct gb_apb_request_cport_flags *req;
++ u32 connection_flags;
++ int ret;
++
++ req = kzalloc(sizeof(*req), GFP_KERNEL);
++ if (!req)
++ return -ENOMEM;
++
++ connection_flags = 0;
++ if (flags & GB_CONNECTION_FLAG_CONTROL)
++ connection_flags |= GB_APB_CPORT_FLAG_CONTROL;
++ if (flags & GB_CONNECTION_FLAG_HIGH_PRIO)
++ connection_flags |= GB_APB_CPORT_FLAG_HIGH_PRIO;
++
++ req->flags = cpu_to_le32(connection_flags);
++
++ dev_dbg(&hd->dev, "%s - cport = %u, flags = %02x\n", __func__,
++ cport_id, connection_flags);
++
++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_CPORT_FLAGS,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, cport_id, 0,
++ req, sizeof(*req), ES2_USB_CTRL_TIMEOUT);
++ if (ret != sizeof(*req)) {
++ dev_err(&udev->dev, "failed to set cport flags for port %d\n",
++ cport_id);
++ if (ret >= 0)
++ ret = -EIO;
++
++ goto out;
++ }
++
++ ret = 0;
++out:
++ kfree(req);
++
++ return ret;
++}
++
++static int es2_cport_connected(struct gb_host_device *hd, u16 cport_id)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct device *dev = &es2->usb_dev->dev;
++ struct arpc_cport_connected_req req;
++ int ret;
++
++ req.cport_id = cpu_to_le16(cport_id);
++ ret = arpc_sync(es2, ARPC_TYPE_CPORT_CONNECTED, &req, sizeof(req),
++ NULL, ES2_ARPC_CPORT_TIMEOUT);
++ if (ret) {
++ dev_err(dev, "failed to set connected state for cport %u: %d\n",
++ cport_id, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int es2_cport_flush(struct gb_host_device *hd, u16 cport_id)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct device *dev = &es2->usb_dev->dev;
++ struct arpc_cport_flush_req req;
++ int ret;
++
++ req.cport_id = cpu_to_le16(cport_id);
++ ret = arpc_sync(es2, ARPC_TYPE_CPORT_FLUSH, &req, sizeof(req),
++ NULL, ES2_ARPC_CPORT_TIMEOUT);
++ if (ret) {
++ dev_err(dev, "failed to flush cport %u: %d\n", cport_id, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int es2_cport_shutdown(struct gb_host_device *hd, u16 cport_id,
++ u8 phase, unsigned int timeout)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct device *dev = &es2->usb_dev->dev;
++ struct arpc_cport_shutdown_req req;
++ int result;
++ int ret;
++
++ if (timeout > U16_MAX)
++ return -EINVAL;
++
++ req.cport_id = cpu_to_le16(cport_id);
++ req.timeout = cpu_to_le16(timeout);
++ req.phase = phase;
++ ret = arpc_sync(es2, ARPC_TYPE_CPORT_SHUTDOWN, &req, sizeof(req),
++ &result, ES2_ARPC_CPORT_TIMEOUT + timeout);
++ if (ret) {
++ dev_err(dev, "failed to send shutdown over cport %u: %d (%d)\n",
++ cport_id, ret, result);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int es2_cport_quiesce(struct gb_host_device *hd, u16 cport_id,
++ size_t peer_space, unsigned int timeout)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct device *dev = &es2->usb_dev->dev;
++ struct arpc_cport_quiesce_req req;
++ int result;
++ int ret;
++
++ if (peer_space > U16_MAX)
++ return -EINVAL;
++
++ if (timeout > U16_MAX)
++ return -EINVAL;
++
++ req.cport_id = cpu_to_le16(cport_id);
++ req.peer_space = cpu_to_le16(peer_space);
++ req.timeout = cpu_to_le16(timeout);
++ ret = arpc_sync(es2, ARPC_TYPE_CPORT_QUIESCE, &req, sizeof(req),
++ &result, ES2_ARPC_CPORT_TIMEOUT + timeout);
++ if (ret) {
++ dev_err(dev, "failed to quiesce cport %u: %d (%d)\n",
++ cport_id, ret, result);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int es2_cport_clear(struct gb_host_device *hd, u16 cport_id)
++{
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct device *dev = &es2->usb_dev->dev;
++ struct arpc_cport_clear_req req;
++ int ret;
++
++ req.cport_id = cpu_to_le16(cport_id);
++ ret = arpc_sync(es2, ARPC_TYPE_CPORT_CLEAR, &req, sizeof(req),
++ NULL, ES2_ARPC_CPORT_TIMEOUT);
++ if (ret) {
++ dev_err(dev, "failed to clear cport %u: %d\n", cport_id, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int latency_tag_enable(struct gb_host_device *hd, u16 cport_id)
++{
++ int retval;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_LATENCY_TAG_EN,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, cport_id, 0, NULL,
++ 0, ES2_USB_CTRL_TIMEOUT);
++
++ if (retval < 0)
++ dev_err(&udev->dev, "Cannot enable latency tag for cport %d\n",
++ cport_id);
++ return retval;
++}
++
++static int latency_tag_disable(struct gb_host_device *hd, u16 cport_id)
++{
++ int retval;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_LATENCY_TAG_DIS,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, cport_id, 0, NULL,
++ 0, ES2_USB_CTRL_TIMEOUT);
++
++ if (retval < 0)
++ dev_err(&udev->dev, "Cannot disable latency tag for cport %d\n",
++ cport_id);
++ return retval;
++}
++
++static int timesync_enable(struct gb_host_device *hd, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk)
++{
++ int retval;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++ struct gb_control_timesync_enable_request *request;
++
++ request = kzalloc(sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ request->count = count;
++ request->frame_time = cpu_to_le64(frame_time);
++ request->strobe_delay = cpu_to_le32(strobe_delay);
++ request->refclk = cpu_to_le32(refclk);
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_TIMESYNC_ENABLE,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, 0, 0, request,
++ sizeof(*request), ES2_USB_CTRL_TIMEOUT);
++ if (retval < 0)
++ dev_err(&udev->dev, "Cannot enable timesync %d\n", retval);
++
++ kfree(request);
++ return retval;
++}
++
++static int timesync_disable(struct gb_host_device *hd)
++{
++ int retval;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_TIMESYNC_DISABLE,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, 0, 0, NULL,
++ 0, ES2_USB_CTRL_TIMEOUT);
++ if (retval < 0)
++ dev_err(&udev->dev, "Cannot disable timesync %d\n", retval);
++
++ return retval;
++}
++
++static int timesync_authoritative(struct gb_host_device *hd, u64 *frame_time)
++{
++ int retval, i;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++ struct timesync_authoritative_request *request;
++
++ request = kzalloc(sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
++ request->frame_time[i] = cpu_to_le64(frame_time[i]);
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_TIMESYNC_AUTHORITATIVE,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, 0, 0, request,
++ sizeof(*request), ES2_USB_CTRL_TIMEOUT);
++ if (retval < 0)
++ dev_err(&udev->dev, "Cannot timesync authoritative out %d\n", retval);
++
++ kfree(request);
++ return retval;
++}
++
++static int timesync_get_last_event(struct gb_host_device *hd, u64 *frame_time)
++{
++ int retval;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ struct usb_device *udev = es2->usb_dev;
++ __le64 *response_frame_time;
++
++ response_frame_time = kzalloc(sizeof(*response_frame_time), GFP_KERNEL);
++ if (!response_frame_time)
++ return -ENOMEM;
++
++ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
++ GB_APB_REQUEST_TIMESYNC_GET_LAST_EVENT,
++ USB_DIR_IN | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, 0, 0, response_frame_time,
++ sizeof(*response_frame_time),
++ ES2_USB_CTRL_TIMEOUT);
++
++ if (retval != sizeof(*response_frame_time)) {
++ dev_err(&udev->dev, "Cannot get last TimeSync event: %d\n",
++ retval);
++
++ if (retval >= 0)
++ retval = -EIO;
++
++ goto out;
++ }
++ *frame_time = le64_to_cpu(*response_frame_time);
++ retval = 0;
++out:
++ kfree(response_frame_time);
++ return retval;
++}
++
++static struct gb_hd_driver es2_driver = {
++ .hd_priv_size = sizeof(struct es2_ap_dev),
++ .message_send = message_send,
++ .message_cancel = message_cancel,
++ .cport_allocate = es2_cport_allocate,
++ .cport_release = es2_cport_release,
++ .cport_enable = cport_enable,
++ .cport_connected = es2_cport_connected,
++ .cport_flush = es2_cport_flush,
++ .cport_shutdown = es2_cport_shutdown,
++ .cport_quiesce = es2_cport_quiesce,
++ .cport_clear = es2_cport_clear,
++ .latency_tag_enable = latency_tag_enable,
++ .latency_tag_disable = latency_tag_disable,
++ .output = output,
++ .timesync_enable = timesync_enable,
++ .timesync_disable = timesync_disable,
++ .timesync_authoritative = timesync_authoritative,
++ .timesync_get_last_event = timesync_get_last_event,
++};
++
++/* Common function to report consistent warnings based on URB status */
++static int check_urb_status(struct urb *urb)
++{
++ struct device *dev = &urb->dev->dev;
++ int status = urb->status;
++
++ switch (status) {
++ case 0:
++ return 0;
++
++ case -EOVERFLOW:
++ dev_err(dev, "%s: overflow actual length is %d\n",
++ __func__, urb->actual_length);
++ case -ECONNRESET:
++ case -ENOENT:
++ case -ESHUTDOWN:
++ case -EILSEQ:
++ case -EPROTO:
++ /* device is gone, stop sending */
++ return status;
++ }
++ dev_err(dev, "%s: unknown status %d\n", __func__, status);
++
++ return -EAGAIN;
++}
++
++static void es2_destroy(struct es2_ap_dev *es2)
++{
++ struct usb_device *udev;
++ struct urb *urb;
++ int i;
++
++ debugfs_remove(es2->apb_log_enable_dentry);
++ usb_log_disable(es2);
++
++ /* Tear down everything! */
++ for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
++ urb = es2->cport_out_urb[i];
++ usb_kill_urb(urb);
++ usb_free_urb(urb);
++ es2->cport_out_urb[i] = NULL;
++ es2->cport_out_urb_busy[i] = false; /* just to be anal */
++ }
++
++ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
++ usb_free_urb(es2->arpc_urb[i]);
++ kfree(es2->arpc_buffer[i]);
++ es2->arpc_buffer[i] = NULL;
++ }
++
++ for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
++ usb_free_urb(es2->cport_in.urb[i]);
++ kfree(es2->cport_in.buffer[i]);
++ es2->cport_in.buffer[i] = NULL;
++ }
++
++ /* release reserved CDSI0 and CDSI1 cports */
++ gb_hd_cport_release_reserved(es2->hd, ES2_CPORT_CDSI1);
++ gb_hd_cport_release_reserved(es2->hd, ES2_CPORT_CDSI0);
++
++ udev = es2->usb_dev;
++ gb_hd_put(es2->hd);
++
++ usb_put_dev(udev);
++}
++
++static void cport_in_callback(struct urb *urb)
++{
++ struct gb_host_device *hd = urb->context;
++ struct device *dev = &urb->dev->dev;
++ struct gb_operation_msg_hdr *header;
++ int status = check_urb_status(urb);
++ int retval;
++ u16 cport_id;
++
++ if (status) {
++ if ((status == -EAGAIN) || (status == -EPROTO))
++ goto exit;
++
++ /* The urb is being unlinked */
++ if (status == -ENOENT || status == -ESHUTDOWN)
++ return;
++
++ dev_err(dev, "urb cport in error %d (dropped)\n", status);
++ return;
++ }
++
++ if (urb->actual_length < sizeof(*header)) {
++ dev_err(dev, "short message received\n");
++ goto exit;
++ }
++
++ /* Extract the CPort id, which is packed in the message header */
++ header = urb->transfer_buffer;
++ cport_id = gb_message_cport_unpack(header);
++
++ if (cport_id_valid(hd, cport_id)) {
++ greybus_data_rcvd(hd, cport_id, urb->transfer_buffer,
++ urb->actual_length);
++ } else {
++ dev_err(dev, "invalid cport id %u received\n", cport_id);
++ }
++exit:
++ /* put our urb back in the request pool */
++ retval = usb_submit_urb(urb, GFP_ATOMIC);
++ if (retval)
++ dev_err(dev, "failed to resubmit in-urb: %d\n", retval);
++}
++
++static void cport_out_callback(struct urb *urb)
++{
++ struct gb_message *message = urb->context;
++ struct gb_host_device *hd = message->operation->connection->hd;
++ struct es2_ap_dev *es2 = hd_to_es2(hd);
++ int status = check_urb_status(urb);
++ unsigned long flags;
++
++ gb_message_cport_clear(message->header);
++
++ spin_lock_irqsave(&es2->cport_out_urb_lock, flags);
++ message->hcpriv = NULL;
++ spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags);
++
++ /*
++ * Tell the submitter that the message send (attempt) is
++ * complete, and report the status.
++ */
++ greybus_message_sent(hd, message, status);
++
++ free_urb(es2, urb);
++}
++
++static struct arpc *arpc_alloc(void *payload, u16 size, u8 type)
++{
++ struct arpc *rpc;
++
++ if (size + sizeof(*rpc->req) > ARPC_OUT_SIZE_MAX)
++ return NULL;
++
++ rpc = kzalloc(sizeof(*rpc), GFP_KERNEL);
++ if (!rpc)
++ return NULL;
++
++ INIT_LIST_HEAD(&rpc->list);
++ rpc->req = kzalloc(sizeof(*rpc->req) + size, GFP_KERNEL);
++ if (!rpc->req)
++ goto err_free_rpc;
++
++ rpc->resp = kzalloc(sizeof(*rpc->resp), GFP_KERNEL);
++ if (!rpc->resp)
++ goto err_free_req;
++
++ rpc->req->type = type;
++ rpc->req->size = cpu_to_le16(sizeof(rpc->req) + size);
++ memcpy(rpc->req->data, payload, size);
++
++ init_completion(&rpc->response_received);
++
++ return rpc;
++
++err_free_req:
++ kfree(rpc->req);
++err_free_rpc:
++ kfree(rpc);
++
++ return NULL;
++}
++
++static void arpc_free(struct arpc *rpc)
++{
++ kfree(rpc->req);
++ kfree(rpc->resp);
++ kfree(rpc);
++}
++
++static struct arpc *arpc_find(struct es2_ap_dev *es2, __le16 id)
++{
++ struct arpc *rpc;
++
++ list_for_each_entry(rpc, &es2->arpcs, list) {
++ if (rpc->req->id == id)
++ return rpc;
++ }
++
++ return NULL;
++}
++
++static void arpc_add(struct es2_ap_dev *es2, struct arpc *rpc)
++{
++ rpc->active = true;
++ rpc->req->id = cpu_to_le16(es2->arpc_id_cycle++);
++ list_add_tail(&rpc->list, &es2->arpcs);
++}
++
++static void arpc_del(struct es2_ap_dev *es2, struct arpc *rpc)
++{
++ if (rpc->active) {
++ rpc->active = false;
++ list_del(&rpc->list);
++ }
++}
++
++static int arpc_send(struct es2_ap_dev *es2, struct arpc *rpc, int timeout)
++{
++ struct usb_device *udev = es2->usb_dev;
++ int retval;
++
++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++ GB_APB_REQUEST_ARPC_RUN,
++ USB_DIR_OUT | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE,
++ 0, 0,
++ rpc->req, le16_to_cpu(rpc->req->size),
++ ES2_USB_CTRL_TIMEOUT);
++ if (retval != le16_to_cpu(rpc->req->size)) {
++ dev_err(&udev->dev,
++ "failed to send ARPC request %d: %d\n",
++ rpc->req->type, retval);
++ if (retval > 0)
++ retval = -EIO;
++ return retval;
++ }
++
++ return 0;
++}
++
++static int arpc_sync(struct es2_ap_dev *es2, u8 type, void *payload,
++ size_t size, int *result, unsigned int timeout)
++{
++ struct arpc *rpc;
++ unsigned long flags;
++ int retval;
++
++ if (result)
++ *result = 0;
++
++ rpc = arpc_alloc(payload, size, type);
++ if (!rpc)
++ return -ENOMEM;
++
++ spin_lock_irqsave(&es2->arpc_lock, flags);
++ arpc_add(es2, rpc);
++ spin_unlock_irqrestore(&es2->arpc_lock, flags);
++
++ retval = arpc_send(es2, rpc, timeout);
++ if (retval)
++ goto out_arpc_del;
++
++ retval = wait_for_completion_interruptible_timeout(
++ &rpc->response_received,
++ msecs_to_jiffies(timeout));
++ if (retval <= 0) {
++ if (!retval)
++ retval = -ETIMEDOUT;
++ goto out_arpc_del;
++ }
++
++ if (rpc->resp->result) {
++ retval = -EREMOTEIO;
++ if (result)
++ *result = rpc->resp->result;
++ } else {
++ retval = 0;
++ }
++
++out_arpc_del:
++ spin_lock_irqsave(&es2->arpc_lock, flags);
++ arpc_del(es2, rpc);
++ spin_unlock_irqrestore(&es2->arpc_lock, flags);
++ arpc_free(rpc);
++
++ if (retval < 0 && retval != -EREMOTEIO) {
++ dev_err(&es2->usb_dev->dev,
++ "failed to execute ARPC: %d\n", retval);
++ }
++
++ return retval;
++}
++
++static void arpc_in_callback(struct urb *urb)
++{
++ struct es2_ap_dev *es2 = urb->context;
++ struct device *dev = &urb->dev->dev;
++ int status = check_urb_status(urb);
++ struct arpc *rpc;
++ struct arpc_response_message *resp;
++ unsigned long flags;
++ int retval;
++
++ if (status) {
++ if ((status == -EAGAIN) || (status == -EPROTO))
++ goto exit;
++
++ /* The urb is being unlinked */
++ if (status == -ENOENT || status == -ESHUTDOWN)
++ return;
++
++ dev_err(dev, "arpc in-urb error %d (dropped)\n", status);
++ return;
++ }
++
++ if (urb->actual_length < sizeof(*resp)) {
++ dev_err(dev, "short aprc response received\n");
++ goto exit;
++ }
++
++ resp = urb->transfer_buffer;
++ spin_lock_irqsave(&es2->arpc_lock, flags);
++ rpc = arpc_find(es2, resp->id);
++ if (!rpc) {
++ dev_err(dev, "invalid arpc response id received: %u\n",
++ le16_to_cpu(resp->id));
++ spin_unlock_irqrestore(&es2->arpc_lock, flags);
++ goto exit;
++ }
++
++ arpc_del(es2, rpc);
++ memcpy(rpc->resp, resp, sizeof(*resp));
++ complete(&rpc->response_received);
++ spin_unlock_irqrestore(&es2->arpc_lock, flags);
++
++exit:
++ /* put our urb back in the request pool */
++ retval = usb_submit_urb(urb, GFP_ATOMIC);
++ if (retval)
++ dev_err(dev, "failed to resubmit arpc in-urb: %d\n", retval);
++}
++
++#define APB1_LOG_MSG_SIZE 64
++static void apb_log_get(struct es2_ap_dev *es2, char *buf)
++{
++ int retval;
++
++ do {
++ retval = usb_control_msg(es2->usb_dev,
++ usb_rcvctrlpipe(es2->usb_dev, 0),
++ GB_APB_REQUEST_LOG,
++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
++ 0x00, 0x00,
++ buf,
++ APB1_LOG_MSG_SIZE,
++ ES2_USB_CTRL_TIMEOUT);
++ if (retval > 0)
++ kfifo_in(&es2->apb_log_fifo, buf, retval);
++ } while (retval > 0);
++}
++
++static int apb_log_poll(void *data)
++{
++ struct es2_ap_dev *es2 = data;
++ char *buf;
++
++ buf = kmalloc(APB1_LOG_MSG_SIZE, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ while (!kthread_should_stop()) {
++ msleep(1000);
++ apb_log_get(es2, buf);
++ }
++
++ kfree(buf);
++
++ return 0;
++}
++
++static ssize_t apb_log_read(struct file *f, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct es2_ap_dev *es2 = f->f_inode->i_private;
++ ssize_t ret;
++ size_t copied;
++ char *tmp_buf;
++
++ if (count > APB1_LOG_SIZE)
++ count = APB1_LOG_SIZE;
++
++ tmp_buf = kmalloc(count, GFP_KERNEL);
++ if (!tmp_buf)
++ return -ENOMEM;
++
++ copied = kfifo_out(&es2->apb_log_fifo, tmp_buf, count);
++ ret = simple_read_from_buffer(buf, count, ppos, tmp_buf, copied);
++
++ kfree(tmp_buf);
++
++ return ret;
++}
++
++static const struct file_operations apb_log_fops = {
++ .read = apb_log_read,
++};
++
++static void usb_log_enable(struct es2_ap_dev *es2)
++{
++ if (!IS_ERR_OR_NULL(es2->apb_log_task))
++ return;
++
++ /* get log from APB1 */
++ es2->apb_log_task = kthread_run(apb_log_poll, es2, "apb_log");
++ if (IS_ERR(es2->apb_log_task))
++ return;
++ /* XXX We will need to rename this per APB */
++ es2->apb_log_dentry = debugfs_create_file("apb_log", S_IRUGO,
++ gb_debugfs_get(), es2,
++ &apb_log_fops);
++}
++
++static void usb_log_disable(struct es2_ap_dev *es2)
++{
++ if (IS_ERR_OR_NULL(es2->apb_log_task))
++ return;
++
++ debugfs_remove(es2->apb_log_dentry);
++ es2->apb_log_dentry = NULL;
++
++ kthread_stop(es2->apb_log_task);
++ es2->apb_log_task = NULL;
++}
++
++static ssize_t apb_log_enable_read(struct file *f, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct es2_ap_dev *es2 = f->f_inode->i_private;
++ int enable = !IS_ERR_OR_NULL(es2->apb_log_task);
++ char tmp_buf[3];
++
++ sprintf(tmp_buf, "%d\n", enable);
++ return simple_read_from_buffer(buf, count, ppos, tmp_buf, 3);
++}
++
++static ssize_t apb_log_enable_write(struct file *f, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int enable;
++ ssize_t retval;
++ struct es2_ap_dev *es2 = f->f_inode->i_private;
++
++ retval = kstrtoint_from_user(buf, count, 10, &enable);
++ if (retval)
++ return retval;
++
++ if (enable)
++ usb_log_enable(es2);
++ else
++ usb_log_disable(es2);
++
++ return count;
++}
++
++static const struct file_operations apb_log_enable_fops = {
++ .read = apb_log_enable_read,
++ .write = apb_log_enable_write,
++};
++
++static int apb_get_cport_count(struct usb_device *udev)
++{
++ int retval;
++ __le16 *cport_count;
++
++ cport_count = kzalloc(sizeof(*cport_count), GFP_KERNEL);
++ if (!cport_count)
++ return -ENOMEM;
++
++ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
++ GB_APB_REQUEST_CPORT_COUNT,
++ USB_DIR_IN | USB_TYPE_VENDOR |
++ USB_RECIP_INTERFACE, 0, 0, cport_count,
++ sizeof(*cport_count), ES2_USB_CTRL_TIMEOUT);
++ if (retval != sizeof(*cport_count)) {
++ dev_err(&udev->dev, "Cannot retrieve CPort count: %d\n",
++ retval);
++
++ if (retval >= 0)
++ retval = -EIO;
++
++ goto out;
++ }
++
++ retval = le16_to_cpu(*cport_count);
++
++ /* We need to fit a CPort ID in one byte of a message header */
++ if (retval > U8_MAX) {
++ retval = U8_MAX;
++ dev_warn(&udev->dev, "Limiting number of CPorts to U8_MAX\n");
++ }
++
++out:
++ kfree(cport_count);
++ return retval;
++}
++
++/*
++ * The ES2 USB Bridge device has 15 endpoints
++ * 1 Control - usual USB stuff + AP -> APBridgeA messages
++ * 7 Bulk IN - CPort data in
++ * 7 Bulk OUT - CPort data out
++ */
++static int ap_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ struct es2_ap_dev *es2;
++ struct gb_host_device *hd;
++ struct usb_device *udev;
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ __u8 ep_addr;
++ int retval;
++ int i;
++ int num_cports;
++ bool bulk_out_found = false;
++ bool bulk_in_found = false;
++ bool arpc_in_found = false;
++
++ udev = usb_get_dev(interface_to_usbdev(interface));
++
++ num_cports = apb_get_cport_count(udev);
++ if (num_cports < 0) {
++ usb_put_dev(udev);
++ dev_err(&udev->dev, "Cannot retrieve CPort count: %d\n",
++ num_cports);
++ return num_cports;
++ }
++
++ hd = gb_hd_create(&es2_driver, &udev->dev, ES2_GBUF_MSG_SIZE_MAX,
++ num_cports);
++ if (IS_ERR(hd)) {
++ usb_put_dev(udev);
++ return PTR_ERR(hd);
++ }
++
++ es2 = hd_to_es2(hd);
++ es2->hd = hd;
++ es2->usb_intf = interface;
++ es2->usb_dev = udev;
++ spin_lock_init(&es2->cport_out_urb_lock);
++ INIT_KFIFO(es2->apb_log_fifo);
++ usb_set_intfdata(interface, es2);
++
++ /*
++ * Reserve the CDSI0 and CDSI1 CPorts so they won't be allocated
++ * dynamically.
++ */
++ retval = gb_hd_cport_reserve(hd, ES2_CPORT_CDSI0);
++ if (retval)
++ goto error;
++ retval = gb_hd_cport_reserve(hd, ES2_CPORT_CDSI1);
++ if (retval)
++ goto error;
++
++ /* find all bulk endpoints */
++ iface_desc = interface->cur_altsetting;
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++ endpoint = &iface_desc->endpoint[i].desc;
++ ep_addr = endpoint->bEndpointAddress;
++
++ if (usb_endpoint_is_bulk_in(endpoint)) {
++ if (!bulk_in_found) {
++ es2->cport_in.endpoint = ep_addr;
++ bulk_in_found = true;
++ } else if (!arpc_in_found) {
++ es2->arpc_endpoint_in = ep_addr;
++ arpc_in_found = true;
++ } else {
++ dev_warn(&udev->dev,
++ "Unused bulk IN endpoint found: 0x%02x\n",
++ ep_addr);
++ }
++ continue;
++ }
++ if (usb_endpoint_is_bulk_out(endpoint)) {
++ if (!bulk_out_found) {
++ es2->cport_out_endpoint = ep_addr;
++ bulk_out_found = true;
++ } else {
++ dev_warn(&udev->dev,
++ "Unused bulk OUT endpoint found: 0x%02x\n",
++ ep_addr);
++ }
++ continue;
++ }
++ dev_warn(&udev->dev,
++ "Unknown endpoint type found, address 0x%02x\n",
++ ep_addr);
++ }
++ if (!bulk_in_found || !arpc_in_found || !bulk_out_found) {
++ dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
++ retval = -ENODEV;
++ goto error;
++ }
++
++ /* Allocate buffers for our cport in messages */
++ for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
++ struct urb *urb;
++ u8 *buffer;
++
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ retval = -ENOMEM;
++ goto error;
++ }
++ es2->cport_in.urb[i] = urb;
++
++ buffer = kmalloc(ES2_GBUF_MSG_SIZE_MAX, GFP_KERNEL);
++ if (!buffer) {
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ usb_fill_bulk_urb(urb, udev,
++ usb_rcvbulkpipe(udev, es2->cport_in.endpoint),
++ buffer, ES2_GBUF_MSG_SIZE_MAX,
++ cport_in_callback, hd);
++
++ es2->cport_in.buffer[i] = buffer;
++ }
++
++ /* Allocate buffers for ARPC in messages */
++ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
++ struct urb *urb;
++ u8 *buffer;
++
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ retval = -ENOMEM;
++ goto error;
++ }
++ es2->arpc_urb[i] = urb;
++
++ buffer = kmalloc(ARPC_IN_SIZE_MAX, GFP_KERNEL);
++ if (!buffer) {
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ usb_fill_bulk_urb(urb, udev,
++ usb_rcvbulkpipe(udev,
++ es2->arpc_endpoint_in),
++ buffer, ARPC_IN_SIZE_MAX,
++ arpc_in_callback, es2);
++
++ es2->arpc_buffer[i] = buffer;
++ }
++
++ /* Allocate urbs for our CPort OUT messages */
++ for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
++ struct urb *urb;
++
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ es2->cport_out_urb[i] = urb;
++ es2->cport_out_urb_busy[i] = false; /* just to be anal */
++ }
++
++ /* XXX We will need to rename this per APB */
++ es2->apb_log_enable_dentry = debugfs_create_file("apb_log_enable",
++ (S_IWUSR | S_IRUGO),
++ gb_debugfs_get(), es2,
++ &apb_log_enable_fops);
++
++ INIT_LIST_HEAD(&es2->arpcs);
++ spin_lock_init(&es2->arpc_lock);
++
++ if (es2_arpc_in_enable(es2))
++ goto error;
++
++ retval = gb_hd_add(hd);
++ if (retval)
++ goto err_disable_arpc_in;
++
++ retval = es2_cport_in_enable(es2, &es2->cport_in);
++ if (retval)
++ goto err_hd_del;
++
++ return 0;
++
++err_hd_del:
++ gb_hd_del(hd);
++err_disable_arpc_in:
++ es2_arpc_in_disable(es2);
++error:
++ es2_destroy(es2);
++
++ return retval;
++}
++
++static void ap_disconnect(struct usb_interface *interface)
++{
++ struct es2_ap_dev *es2 = usb_get_intfdata(interface);
++
++ gb_hd_del(es2->hd);
++
++ es2_cport_in_disable(es2, &es2->cport_in);
++ es2_arpc_in_disable(es2);
++
++ es2_destroy(es2);
++}
++
++static struct usb_driver es2_ap_driver = {
++ .name = "es2_ap_driver",
++ .probe = ap_probe,
++ .disconnect = ap_disconnect,
++ .id_table = id_table,
++ .soft_unbind = 1,
++};
++
++module_usb_driver(es2_ap_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
diff --git a/greybus_firmware.patch b/greybus_firmware.patch
new file mode 100644
index 00000000000000..aa4c4f041c4464
--- /dev/null
+++ b/greybus_firmware.patch
@@ -0,0 +1,2429 @@
+---
+ drivers/greybus/Documentation/firmware/authenticate.c | 139 ++
+ drivers/greybus/Documentation/firmware/firmware-management | 333 ++++++
+ drivers/greybus/Documentation/firmware/firmware.c | 262 ++++
+ drivers/greybus/firmware.h | 42
+ drivers/greybus/fw-core.c | 312 +++++
+ drivers/greybus/fw-download.c | 465 ++++++++
+ drivers/greybus/fw-management.c | 721 +++++++++++++
+ drivers/greybus/greybus_firmware.h | 120 ++
+ 8 files changed, 2394 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/Documentation/firmware/authenticate.c
+@@ -0,0 +1,139 @@
++/*
++ * Sample code to test CAP protocol
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include "../../greybus_authentication.h"
++
++struct cap_ioc_get_endpoint_uid uid;
++struct cap_ioc_get_ims_certificate cert = {
++ .certificate_class = 0,
++ .certificate_id = 0,
++};
++
++struct cap_ioc_authenticate authenticate = {
++ .auth_type = 0,
++ .challenge = {0},
++};
++
++int main(int argc, char *argv[])
++{
++ unsigned int timeout = 10000;
++ char *capdev;
++ int fd, ret;
++
++ /* Make sure arguments are correct */
++ if (argc != 2) {
++ printf("\nUsage: ./firmware <Path of the gb-cap-X dev>\n");
++ return 0;
++ }
++
++ capdev = argv[1];
++
++ printf("Opening %s authentication device\n", capdev);
++
++ fd = open(capdev, O_RDWR);
++ if (fd < 0) {
++ printf("Failed to open: %s\n", capdev);
++ return -1;
++ }
++
++ /* Get UID */
++ printf("Get UID\n");
++
++ ret = ioctl(fd, CAP_IOC_GET_ENDPOINT_UID, &uid);
++ if (ret < 0) {
++ printf("Failed to get UID: %s (%d)\n", capdev, ret);
++ ret = -1;
++ goto close_fd;
++ }
++
++ printf("UID received: 0x%llx\n", *(long long unsigned int *)(uid.uid));
++
++ /* Get certificate */
++ printf("Get IMS certificate\n");
++
++ ret = ioctl(fd, CAP_IOC_GET_IMS_CERTIFICATE, &cert);
++ if (ret < 0) {
++ printf("Failed to get IMS certificate: %s (%d)\n", capdev, ret);
++ ret = -1;
++ goto close_fd;
++ }
++
++ printf("IMS Certificate size: %d\n", cert.cert_size);
++
++ /* Authenticate */
++ printf("Authenticate module\n");
++
++ memcpy(authenticate.uid, uid.uid, 8);
++
++ ret = ioctl(fd, CAP_IOC_AUTHENTICATE, &authenticate);
++ if (ret < 0) {
++ printf("Failed to authenticate module: %s (%d)\n", capdev, ret);
++ ret = -1;
++ goto close_fd;
++ }
++
++ printf("Authenticated, result (%02x), sig-size (%02x)\n",
++ authenticate.result_code, authenticate.signature_size);
++
++close_fd:
++ close(fd);
++
++ return ret;
++}
+--- /dev/null
++++ b/drivers/greybus/Documentation/firmware/firmware-management
+@@ -0,0 +1,333 @@
++
++Firmware Management
++-------------------
++ Copyright 2016 Google Inc.
++ Copyright 2016 Linaro Ltd.
++
++Interface-Manifest
++------------------
++
++All firmware packages on the Modules or Interfaces are managed by a special
++Firmware Management Protocol. To support Firmware Management by the AP, the
++Interface Manifest shall at least contain the Firmware Management Bundle and a
++Firmware Management Protocol CPort within it.
++
++The bundle may contain additional CPorts based on the extra functionality
++required to manage firmware packages.
++
++For example, this is how the Firmware Management part of the Interface Manifest
++may look like:
++
++ ; Firmware Management Bundle (Bundle 1):
++ [bundle-descriptor 1]
++ class = 0x16
++
++ ; (Mandatory) Firmware Management Protocol on CPort 1
++ [cport-descriptor 2]
++ bundle = 1
++ protocol = 0x18
++
++ ; (Optional) Firmware Download Protocol on CPort 2
++ [cport-descriptor 1]
++ bundle = 1
++ protocol = 0x17
++
++ ; (Optional) SPI protocol on CPort 3
++ [cport-descriptor 3]
++ bundle = 1
++ protocol = 0x0b
++
++ ; (Optional) Component Authentication Protocol (CAP) on CPort 4
++ [cport-descriptor 4]
++ bundle = 1
++ protocol = 0x19
++
++
++Sysfs Interfaces - Firmware Management
++--------------------------------------
++
++The Firmware Management Protocol interacts with Userspace using the character
++device interface. The character device will be present in /dev/ directory
++and will be named gb-fw-mgmt-<N>. The number <N> is assigned at runtime.
++
++Identifying the Character Device
++================================
++
++There can be multiple devices present in /dev/ directory with name gb-fw-mgmt-N
++and user first needs to identify the character device used for
++firmware-management for a particular interface.
++
++The Firmware Management core creates a device of class 'gb_fw_mgmt', which shall
++be used by the user to identify the right character device for it. The class
++device is created within the Bundle directory for a particular Interface.
++
++For example this is how the class-device can be present:
++
++/sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/gb_fw_mgmt/gb-fw-mgmt-0
++
++The last name in this path: gb-fw-mgmt-0 is precisely the name of the char
++device and so the device in this case will be:
++
++/dev/gb-fw-mgmt-0.
++
++Operations on the Char device
++=============================
++
++The Character device (gb-fw-mgmt-0 in example) can be opened by the userspace
++application and it can perform various 'ioctl' operations on the device. The
++device doesn't support any read/write operations.
++
++Following are the IOCTLs and their data structures available to the user:
++
++/* IOCTL support */
++#define GB_FW_LOAD_METHOD_UNIPRO 0x01
++#define GB_FW_LOAD_METHOD_INTERNAL 0x02
++
++#define GB_FW_LOAD_STATUS_FAILED 0x00
++#define GB_FW_LOAD_STATUS_UNVALIDATED 0x01
++#define GB_FW_LOAD_STATUS_VALIDATED 0x02
++#define GB_FW_LOAD_STATUS_VALIDATION_FAILED 0x03
++
++#define GB_FW_BACKEND_FW_STATUS_SUCCESS 0x01
++#define GB_FW_BACKEND_FW_STATUS_FAIL_FIND 0x02
++#define GB_FW_BACKEND_FW_STATUS_FAIL_FETCH 0x03
++#define GB_FW_BACKEND_FW_STATUS_FAIL_WRITE 0x04
++#define GB_FW_BACKEND_FW_STATUS_INT 0x05
++#define GB_FW_BACKEND_FW_STATUS_RETRY 0x06
++#define GB_FW_BACKEND_FW_STATUS_NOT_SUPPORTED 0x07
++
++#define GB_FW_BACKEND_VERSION_STATUS_SUCCESS 0x01
++#define GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE 0x02
++#define GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED 0x03
++#define GB_FW_BACKEND_VERSION_STATUS_RETRY 0x04
++#define GB_FW_BACKEND_VERSION_STATUS_FAIL_INT 0x05
++
++
++struct fw_mgmt_ioc_get_intf_version {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u16 major;
++ __u16 minor;
++} __attribute__ ((__packed__));
++
++struct fw_mgmt_ioc_get_backend_version {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u16 major;
++ __u16 minor;
++ __u8 status;
++} __attribute__ ((__packed__));
++
++struct fw_mgmt_ioc_intf_load_and_validate {
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++ __u8 load_method;
++ __u8 status;
++ __u16 major;
++ __u16 minor;
++} __packed;
++
++struct fw_mgmt_ioc_backend_fw_update {
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++ __u8 status;
++} __packed;
++
++#define FW_MGMT_IOCTL_BASE 'S'
++#define FW_MGMT_IOC_GET_INTF_FW _IOR(FW_MGMT_IOCTL_BASE, 0, struct fw_mgmt_ioc_get_intf_version)
++#define FW_MGMT_IOC_GET_BACKEND_FW _IOWR(FW_MGMT_IOCTL_BASE, 1, struct fw_mgmt_ioc_get_backend_version)
++#define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate)
++#define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update)
++#define FW_MGMT_IOC_SET_TIMEOUT_MS _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int)
++#define FW_MGMT_IOC_MODE_SWITCH _IO(FW_MGMT_IOCTL_BASE, 5)
++
++1. FW_MGMT_IOC_GET_INTF_FW:
++
++ This ioctl shall be used by the user to get the version and firmware-tag of
++ the currently running Interface Firmware. All the fields of the 'struct
++ fw_mgmt_ioc_get_fw' are filled by the kernel.
++
++2. FW_MGMT_IOC_GET_BACKEND_FW:
++
++ This ioctl shall be used by the user to get the version of a currently
++ running Backend Interface Firmware identified by a firmware-tag. The user is
++ required to fill the 'firmware_tag' field of the 'struct fw_mgmt_ioc_get_fw'
++ in this case. The 'major' and 'minor' fields are set by the kernel in
++ response.
++
++3. FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE:
++
++ This ioctl shall be used by the user to load an Interface Firmware package on
++ an Interface. The user needs to fill the 'firmware_tag' and 'load_method'
++ fields of the 'struct fw_mgmt_ioc_intf_load_and_validate'. The 'status',
++ 'major' and 'minor' fields are set by the kernel in response.
++
++4. FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE:
++
++ This ioctl shall be used by the user to request an Interface to update a
++ Backend Interface Firmware. The user is required to fill the 'firmware_tag'
++ field of the 'struct fw_mgmt_ioc_get_fw' in this case. The 'status' field is
++ set by the kernel in response.
++
++5. FW_MGMT_IOC_SET_TIMEOUT_MS:
++
++ This ioctl shall be used by the user to increase the timeout interval within
++ which the firmware must get loaded by the Module. The default timeout is 1
++ second. The user needs to pass the timeout in milliseconds.
++
++6. FW_MGMT_IOC_MODE_SWITCH:
++
++ This ioctl shall be used by the user to mode-switch the module to the
++ previously loaded interface firmware. If the interface firmware isn't loaded
++ previously, or if another unsuccessful FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE
++ operation is started after loading interface firmware, then the firmware core
++ wouldn't allow mode-switch.
++
++
++Sysfs Interfaces - Authentication
++---------------------------------
++
++The Component Authentication Protocol interacts with Userspace using the
++character device interface. The character device will be present in /dev/
++directory and will be named gb-authenticate-<N>. The number <N> is assigned at
++runtime.
++
++Identifying the Character Device
++================================
++
++There can be multiple devices present in /dev/ directory with name
++gb-authenticate-N and user first needs to identify the character device used for
++authentication a of particular interface.
++
++The Authentication core creates a device of class 'gb_authenticate', which shall
++be used by the user to identify the right character device for it. The class
++device is created within the Bundle directory for a particular Interface.
++
++For example this is how the class-device can be present:
++
++/sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/gb_authenticate/gb-authenticate-0
++
++The last name in this path: gb-authenticate-0 is precisely the name of the char
++device and so the device in this case will be:
++
++/dev/gb-authenticate-0.
++
++Operations on the Char device
++=============================
++
++The Character device (/dev/gb-authenticate-0 in above example) can be opened by
++the userspace application and it can perform various 'ioctl' operations on the
++device. The device doesn't support any read/write operations.
++
++Following are the IOCTLs and their data structures available to the user:
++
++#define CAP_CERTIFICATE_MAX_SIZE 1600
++#define CAP_SIGNATURE_MAX_SIZE 320
++
++/* Certificate class types */
++#define CAP_CERT_IMS_EAPC 0x00000001
++#define CAP_CERT_IMS_EASC 0x00000002
++#define CAP_CERT_IMS_EARC 0x00000003
++#define CAP_CERT_IMS_IAPC 0x00000004
++#define CAP_CERT_IMS_IASC 0x00000005
++#define CAP_CERT_IMS_IARC 0x00000006
++
++/* IMS Certificate response result codes */
++#define CAP_IMS_RESULT_CERT_FOUND 0x00
++#define CAP_IMS_RESULT_CERT_CLASS_INVAL 0x01
++#define CAP_IMS_RESULT_CERT_CORRUPT 0x02
++#define CAP_IMS_RESULT_CERT_NOT_FOUND 0x03
++
++/* Authentication types */
++#define CAP_AUTH_IMS_PRI 0x00000001
++#define CAP_AUTH_IMS_SEC 0x00000002
++#define CAP_AUTH_IMS_RSA 0x00000003
++
++/* Authenticate response result codes */
++#define CAP_AUTH_RESULT_CR_SUCCESS 0x00
++#define CAP_AUTH_RESULT_CR_BAD_TYPE 0x01
++#define CAP_AUTH_RESULT_CR_WRONG_EP 0x02
++#define CAP_AUTH_RESULT_CR_NO_KEY 0x03
++#define CAP_AUTH_RESULT_CR_SIG_FAIL 0x04
++
++
++/* IOCTL support */
++struct cap_ioc_get_endpoint_uid {
++ __u8 uid[8];
++} __attribute__ ((__packed__));
++
++struct cap_ioc_get_ims_certificate {
++ __u32 certificate_class;
++ __u32 certificate_id;
++
++ __u8 result_code;
++ __u32 cert_size;
++ __u8 certificate[CAP_CERTIFICATE_MAX_SIZE];
++} __attribute__ ((__packed__));
++
++struct cap_ioc_authenticate {
++ __u32 auth_type;
++ __u8 uid[8];
++ __u8 challenge[32];
++
++ __u8 result_code;
++ __u8 response[64];
++ __u32 signature_size;
++ __u8 signature[CAP_SIGNATURE_MAX_SIZE];
++} __attribute__ ((__packed__));
++
++#define CAP_IOCTL_BASE 'C'
++#define CAP_IOC_GET_ENDPOINT_UID _IOR(CAP_IOCTL_BASE, 0, struct cap_ioc_get_endpoint_uid)
++#define CAP_IOC_GET_IMS_CERTIFICATE _IOWR(CAP_IOCTL_BASE, 1, struct cap_ioc_get_ims_certificate)
++#define CAP_IOC_AUTHENTICATE _IOWR(CAP_IOCTL_BASE, 2, struct cap_ioc_authenticate)
++
++
++1. CAP_IOC_GET_ENDPOINT_UID:
++
++ This ioctl shall be used by the user to get the endpoint UID associated with
++ the Interface. All the fields of the 'struct cap_ioc_get_endpoint_uid' are
++ filled by the kernel.
++
++2. CAP_IOC_GET_IMS_CERTIFICATE:
++
++ This ioctl shall be used by the user to retrieve one of the available
++ cryptographic certificates held by the Interface for use in Component
++ Authentication. The user is required to fill the 'certificate_class' and
++ 'certificate_id' field of the 'struct cap_ioc_get_ims_certificate' in this
++ case. The other fields will be set by the kernel in response. The first
++ 'cert_size' bytes of the 'certificate' shall be read by the user and others
++ must be discarded.
++
++3. CAP_IOC_AUTHENTICATE:
++
++ This ioctl shall be used by the user to authenticate the Module attached to
++ an Interface. The user needs to fill the 'auth_type', 'uid', and 'challenge'
++ fields of the 'struct cap_ioc_authenticate'. The other fields will be set by
++ the kernel in response. The first 'signature_size' bytes of the 'signature'
++ shall be read by the user and others must be discarded.
++
++
++Sysfs Interfaces - Firmware Download
++------------------------------------
++
++The Firmware Download Protocol uses the existing Linux Kernel's Firmware class
++and the interface provided to userspace are described in:
++Documentation/firmware_class/.
++
++
++Sysfs Interfaces - SPI Flash
++----------------------------
++
++The SPI flash is exposed in userspace as a MTD device and is created
++within the Bundle directory. For example, this is how the path may look like:
++
++$ ls /sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/spi_master/spi32766/spi32766.0/mtd
++mtd0 mtd0ro
++
++
++Sample Applications
++-------------------
++
++The current directory also provides a firmware.c test application, which can be
++referenced while developing userspace application to talk to firmware-management
++protocol.
++
++The current directory also provides a authenticate.c test application, which can
++be referenced while developing userspace application to talk to
++component authentication protocol.
+--- /dev/null
++++ b/drivers/greybus/Documentation/firmware/firmware.c
+@@ -0,0 +1,262 @@
++/*
++ * Sample code to test firmware-management protocol
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include "../../greybus_firmware.h"
++
++#define FW_DEV_DEFAULT "/dev/gb-fw-mgmt-0"
++#define FW_TAG_INT_DEFAULT "s3f"
++#define FW_TAG_BCND_DEFAULT "bf_01"
++#define FW_UPDATE_TYPE_DEFAULT 0
++#define FW_TIMEOUT_DEFAULT 10000;
++
++static const char *firmware_tag;
++static const char *fwdev = FW_DEV_DEFAULT;
++static int fw_update_type = FW_UPDATE_TYPE_DEFAULT;
++static int fw_timeout = FW_TIMEOUT_DEFAULT;
++
++static struct fw_mgmt_ioc_get_intf_version intf_fw_info;
++static struct fw_mgmt_ioc_get_backend_version backend_fw_info;
++static struct fw_mgmt_ioc_intf_load_and_validate intf_load;
++static struct fw_mgmt_ioc_backend_fw_update backend_update;
++
++static void usage(void)
++{
++ printf("\nUsage: ./firmware <gb-fw-mgmt-X (default: gb-fw-mgmt-0)> <interface: 0, backend: 1 (default: 0)> <firmware-tag> (default: \"s3f\"/\"bf_01\") <timeout (default: 10000 ms)>\n");
++}
++
++static int update_intf_firmware(int fd)
++{
++ int ret;
++
++ /* Get Interface Firmware Version */
++ printf("Get Interface Firmware Version\n");
++
++ ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &intf_fw_info);
++ if (ret < 0) {
++ printf("Failed to get interface firmware version: %s (%d)\n",
++ fwdev, ret);
++ return -1;
++ }
++
++ printf("Interface Firmware tag (%s), major (%d), minor (%d)\n",
++ intf_fw_info.firmware_tag, intf_fw_info.major,
++ intf_fw_info.minor);
++
++ /* Try Interface Firmware load over Unipro */
++ printf("Loading Interface Firmware\n");
++
++ intf_load.load_method = GB_FW_U_LOAD_METHOD_UNIPRO;
++ intf_load.status = 0;
++ intf_load.major = 0;
++ intf_load.minor = 0;
++
++ strncpy((char *)&intf_load.firmware_tag, firmware_tag,
++ GB_FIRMWARE_U_TAG_MAX_SIZE);
++
++ ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load);
++ if (ret < 0) {
++ printf("Failed to load interface firmware: %s (%d)\n", fwdev,
++ ret);
++ return -1;
++ }
++
++ if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED &&
++ intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) {
++ printf("Load status says loading failed: %d\n",
++ intf_load.status);
++ return -1;
++ }
++
++ printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n",
++ firmware_tag, intf_load.major, intf_load.minor,
++ intf_load.status);
++
++ /* Initiate Mode-switch to the newly loaded firmware */
++ printf("Initiate Mode switch\n");
++
++ ret = ioctl(fd, FW_MGMT_IOC_MODE_SWITCH);
++ if (ret < 0)
++ printf("Failed to initiate mode-switch (%d)\n", ret);
++
++ return ret;
++}
++
++static int update_backend_firmware(int fd)
++{
++ int ret;
++
++ /* Get Backend Firmware Version */
++ printf("Getting Backend Firmware Version\n");
++
++ strncpy((char *)&backend_fw_info.firmware_tag, firmware_tag,
++ GB_FIRMWARE_U_TAG_MAX_SIZE);
++
++retry_fw_version:
++ ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &backend_fw_info);
++ if (ret < 0) {
++ printf("Failed to get backend firmware version: %s (%d)\n",
++ fwdev, ret);
++ return -1;
++ }
++
++ printf("Backend Firmware tag (%s), major (%d), minor (%d), status (%d)\n",
++ backend_fw_info.firmware_tag, backend_fw_info.major,
++ backend_fw_info.minor, backend_fw_info.status);
++
++ if (backend_fw_info.status == GB_FW_U_BACKEND_VERSION_STATUS_RETRY)
++ goto retry_fw_version;
++
++ if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS)
++ && (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) {
++ printf("Failed to get backend firmware version: %s (%d)\n",
++ fwdev, backend_fw_info.status);
++ return -1;
++ }
++
++ /* Try Backend Firmware Update over Unipro */
++ printf("Updating Backend Firmware\n");
++
++ strncpy((char *)&backend_update.firmware_tag, firmware_tag,
++ GB_FIRMWARE_U_TAG_MAX_SIZE);
++
++retry_fw_update:
++ backend_update.status = 0;
++
++ ret = ioctl(fd, FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE, &backend_update);
++ if (ret < 0) {
++ printf("Failed to load backend firmware: %s (%d)\n", fwdev, ret);
++ return -1;
++ }
++
++ if (backend_update.status == GB_FW_U_BACKEND_FW_STATUS_RETRY) {
++ printf("Retrying firmware update: %d\n", backend_update.status);
++ goto retry_fw_update;
++ }
++
++ if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) {
++ printf("Load status says loading failed: %d\n",
++ backend_update.status);
++ } else {
++ printf("Backend Firmware (%s) Load done: status: %d\n",
++ firmware_tag, backend_update.status);
++ }
++
++ return 0;
++}
++
++int main(int argc, char *argv[])
++{
++ int fd, ret;
++
++ if (argc > 1 &&
++ (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
++ usage();
++ return -1;
++ }
++
++ if (argc > 1)
++ fwdev = argv[1];
++
++ if (argc > 2)
++ sscanf(argv[2], "%u", &fw_update_type);
++
++ if (argc > 3) {
++ firmware_tag = argv[3];
++ } else if (!fw_update_type) {
++ firmware_tag = FW_TAG_INT_DEFAULT;
++ } else {
++ firmware_tag = FW_TAG_BCND_DEFAULT;
++ }
++
++ if (argc > 4)
++ sscanf(argv[4], "%u", &fw_timeout);
++
++ printf("Trying Firmware update: fwdev: %s, type: %s, tag: %s, timeout: %d\n",
++ fwdev, fw_update_type == 0 ? "interface" : "backend",
++ firmware_tag, fw_timeout);
++
++ printf("Opening %s firmware management device\n", fwdev);
++
++ fd = open(fwdev, O_RDWR);
++ if (fd < 0) {
++ printf("Failed to open: %s\n", fwdev);
++ return -1;
++ }
++
++ /* Set Timeout */
++ printf("Setting timeout to %u ms\n", fw_timeout);
++
++ ret = ioctl(fd, FW_MGMT_IOC_SET_TIMEOUT_MS, &fw_timeout);
++ if (ret < 0) {
++ printf("Failed to set timeout: %s (%d)\n", fwdev, ret);
++ ret = -1;
++ goto close_fd;
++ }
++
++ if (!fw_update_type)
++ ret = update_intf_firmware(fd);
++ else
++ ret = update_backend_firmware(fd);
++
++close_fd:
++ close(fd);
++
++ return ret;
++}
+--- /dev/null
++++ b/drivers/greybus/firmware.h
+@@ -0,0 +1,42 @@
++/*
++ * Greybus Firmware Management Header
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __FIRMWARE_H
++#define __FIRMWARE_H
++
++#include "greybus.h"
++
++#define FW_NAME_PREFIX "gmp_"
++
++/*
++ * Length of the string in format: "FW_NAME_PREFIX""%08x_%08x_%08x_%08x_%s.tftf"
++ * (3 + 1 + 4 * (8 + 1) + 10 + 1 + 4 + 1)
++ */
++#define FW_NAME_SIZE 56
++
++/* Firmware Management Protocol specific functions */
++int fw_mgmt_init(void);
++void fw_mgmt_exit(void);
++struct gb_connection *to_fw_mgmt_connection(struct device *dev);
++int gb_fw_mgmt_request_handler(struct gb_operation *op);
++int gb_fw_mgmt_connection_init(struct gb_connection *connection);
++void gb_fw_mgmt_connection_exit(struct gb_connection *connection);
++
++/* Firmware Download Protocol specific functions */
++int gb_fw_download_request_handler(struct gb_operation *op);
++int gb_fw_download_connection_init(struct gb_connection *connection);
++void gb_fw_download_connection_exit(struct gb_connection *connection);
++
++/* CAP Protocol specific functions */
++int cap_init(void);
++void cap_exit(void);
++int gb_cap_connection_init(struct gb_connection *connection);
++void gb_cap_connection_exit(struct gb_connection *connection);
++
++#endif /* __FIRMWARE_H */
+--- /dev/null
++++ b/drivers/greybus/fw-core.c
+@@ -0,0 +1,312 @@
++/*
++ * Greybus Firmware Core Bundle Driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/firmware.h>
++#include "firmware.h"
++#include "greybus.h"
++#include "spilib.h"
++
++struct gb_fw_core {
++ struct gb_connection *download_connection;
++ struct gb_connection *mgmt_connection;
++ struct gb_connection *spi_connection;
++ struct gb_connection *cap_connection;
++};
++
++static struct spilib_ops *spilib_ops;
++
++struct gb_connection *to_fw_mgmt_connection(struct device *dev)
++{
++ struct gb_fw_core *fw_core = dev_get_drvdata(dev);
++
++ return fw_core->mgmt_connection;
++}
++
++static int gb_fw_spi_connection_init(struct gb_connection *connection)
++{
++ int ret;
++
++ if (!connection)
++ return 0;
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ return ret;
++
++ ret = gb_spilib_master_init(connection, &connection->bundle->dev,
++ spilib_ops);
++ if (ret) {
++ gb_connection_disable(connection);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void gb_fw_spi_connection_exit(struct gb_connection *connection)
++{
++ if (!connection)
++ return;
++
++ gb_spilib_master_exit(connection);
++ gb_connection_disable(connection);
++}
++
++static int gb_fw_core_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_fw_core *fw_core;
++ int ret, i;
++ u16 cport_id;
++ u8 protocol_id;
++
++ fw_core = kzalloc(sizeof(*fw_core), GFP_KERNEL);
++ if (!fw_core)
++ return -ENOMEM;
++
++ /* Parse CPorts and create connections */
++ for (i = 0; i < bundle->num_cports; i++) {
++ cport_desc = &bundle->cport_desc[i];
++ cport_id = le16_to_cpu(cport_desc->id);
++ protocol_id = cport_desc->protocol_id;
++
++ switch (protocol_id) {
++ case GREYBUS_PROTOCOL_FW_MANAGEMENT:
++ /* Disallow multiple Firmware Management CPorts */
++ if (fw_core->mgmt_connection) {
++ dev_err(&bundle->dev,
++ "multiple management CPorts found\n");
++ ret = -EINVAL;
++ goto err_destroy_connections;
++ }
++
++ connection = gb_connection_create(bundle, cport_id,
++ gb_fw_mgmt_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ dev_err(&bundle->dev,
++ "failed to create management connection (%d)\n",
++ ret);
++ goto err_destroy_connections;
++ }
++
++ fw_core->mgmt_connection = connection;
++ break;
++ case GREYBUS_PROTOCOL_FW_DOWNLOAD:
++ /* Disallow multiple Firmware Download CPorts */
++ if (fw_core->download_connection) {
++ dev_err(&bundle->dev,
++ "multiple download CPorts found\n");
++ ret = -EINVAL;
++ goto err_destroy_connections;
++ }
++
++ connection = gb_connection_create(bundle, cport_id,
++ gb_fw_download_request_handler);
++ if (IS_ERR(connection)) {
++ dev_err(&bundle->dev, "failed to create download connection (%ld)\n",
++ PTR_ERR(connection));
++ } else {
++ fw_core->download_connection = connection;
++ }
++
++ break;
++ case GREYBUS_PROTOCOL_SPI:
++ /* Disallow multiple SPI CPorts */
++ if (fw_core->spi_connection) {
++ dev_err(&bundle->dev,
++ "multiple SPI CPorts found\n");
++ ret = -EINVAL;
++ goto err_destroy_connections;
++ }
++
++ connection = gb_connection_create(bundle, cport_id,
++ NULL);
++ if (IS_ERR(connection)) {
++ dev_err(&bundle->dev, "failed to create SPI connection (%ld)\n",
++ PTR_ERR(connection));
++ } else {
++ fw_core->spi_connection = connection;
++ }
++
++ break;
++ case GREYBUS_PROTOCOL_AUTHENTICATION:
++ /* Disallow multiple CAP CPorts */
++ if (fw_core->cap_connection) {
++ dev_err(&bundle->dev, "multiple Authentication CPorts found\n");
++ ret = -EINVAL;
++ goto err_destroy_connections;
++ }
++
++ connection = gb_connection_create(bundle, cport_id,
++ NULL);
++ if (IS_ERR(connection)) {
++ dev_err(&bundle->dev, "failed to create Authentication connection (%ld)\n",
++ PTR_ERR(connection));
++ } else {
++ fw_core->cap_connection = connection;
++ }
++
++ break;
++ default:
++ dev_err(&bundle->dev, "invalid protocol id (0x%02x)\n",
++ protocol_id);
++ ret = -EINVAL;
++ goto err_destroy_connections;
++ }
++ }
++
++ /* Firmware Management connection is mandatory */
++ if (!fw_core->mgmt_connection) {
++ dev_err(&bundle->dev, "missing management connection\n");
++ ret = -ENODEV;
++ goto err_destroy_connections;
++ }
++
++ ret = gb_fw_download_connection_init(fw_core->download_connection);
++ if (ret) {
++ /* We may still be able to work with the Interface */
++ dev_err(&bundle->dev, "failed to initialize firmware download connection, disable it (%d)\n",
++ ret);
++ gb_connection_destroy(fw_core->download_connection);
++ fw_core->download_connection = NULL;
++ }
++
++ ret = gb_fw_spi_connection_init(fw_core->spi_connection);
++ if (ret) {
++ /* We may still be able to work with the Interface */
++ dev_err(&bundle->dev, "failed to initialize SPI connection, disable it (%d)\n",
++ ret);
++ gb_connection_destroy(fw_core->spi_connection);
++ fw_core->spi_connection = NULL;
++ }
++
++ ret = gb_cap_connection_init(fw_core->cap_connection);
++ if (ret) {
++ /* We may still be able to work with the Interface */
++ dev_err(&bundle->dev, "failed to initialize CAP connection, disable it (%d)\n",
++ ret);
++ gb_connection_destroy(fw_core->cap_connection);
++ fw_core->cap_connection = NULL;
++ }
++
++ ret = gb_fw_mgmt_connection_init(fw_core->mgmt_connection);
++ if (ret) {
++ /* We may still be able to work with the Interface */
++ dev_err(&bundle->dev, "failed to initialize firmware management connection, disable it (%d)\n",
++ ret);
++ goto err_exit_connections;
++ }
++
++ greybus_set_drvdata(bundle, fw_core);
++
++ /* FIXME: Remove this after S2 Loader gets runtime PM support */
++ if (!(bundle->intf->quirks & GB_INTERFACE_QUIRK_NO_PM))
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++err_exit_connections:
++ gb_cap_connection_exit(fw_core->cap_connection);
++ gb_fw_spi_connection_exit(fw_core->spi_connection);
++ gb_fw_download_connection_exit(fw_core->download_connection);
++err_destroy_connections:
++ gb_connection_destroy(fw_core->mgmt_connection);
++ gb_connection_destroy(fw_core->cap_connection);
++ gb_connection_destroy(fw_core->spi_connection);
++ gb_connection_destroy(fw_core->download_connection);
++ kfree(fw_core);
++
++ return ret;
++}
++
++static void gb_fw_core_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
++ int ret;
++
++ /* FIXME: Remove this after S2 Loader gets runtime PM support */
++ if (!(bundle->intf->quirks & GB_INTERFACE_QUIRK_NO_PM)) {
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ gb_pm_runtime_get_noresume(bundle);
++ }
++
++ gb_fw_mgmt_connection_exit(fw_core->mgmt_connection);
++ gb_cap_connection_exit(fw_core->cap_connection);
++ gb_fw_spi_connection_exit(fw_core->spi_connection);
++ gb_fw_download_connection_exit(fw_core->download_connection);
++
++ gb_connection_destroy(fw_core->mgmt_connection);
++ gb_connection_destroy(fw_core->cap_connection);
++ gb_connection_destroy(fw_core->spi_connection);
++ gb_connection_destroy(fw_core->download_connection);
++
++ kfree(fw_core);
++}
++
++static const struct greybus_bundle_id gb_fw_core_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FW_MANAGEMENT) },
++ { }
++};
++
++static struct greybus_driver gb_fw_core_driver = {
++ .name = "gb-firmware",
++ .probe = gb_fw_core_probe,
++ .disconnect = gb_fw_core_disconnect,
++ .id_table = gb_fw_core_id_table,
++};
++
++static int fw_core_init(void)
++{
++ int ret;
++
++ ret = fw_mgmt_init();
++ if (ret) {
++ pr_err("Failed to initialize fw-mgmt core (%d)\n", ret);
++ return ret;
++ }
++
++ ret = cap_init();
++ if (ret) {
++ pr_err("Failed to initialize component authentication core (%d)\n",
++ ret);
++ goto fw_mgmt_exit;
++ }
++
++ ret = greybus_register(&gb_fw_core_driver);
++ if (ret)
++ goto cap_exit;
++
++ return 0;
++
++cap_exit:
++ cap_exit();
++fw_mgmt_exit:
++ fw_mgmt_exit();
++
++ return ret;
++}
++module_init(fw_core_init);
++
++static void __exit fw_core_exit(void)
++{
++ greybus_deregister(&gb_fw_core_driver);
++ cap_exit();
++ fw_mgmt_exit();
++}
++module_exit(fw_core_exit);
++
++MODULE_ALIAS("greybus:firmware");
++MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
++MODULE_DESCRIPTION("Greybus Firmware Bundle Driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/greybus/fw-download.c
+@@ -0,0 +1,465 @@
++/*
++ * Greybus Firmware Download Protocol Driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/firmware.h>
++#include <linux/jiffies.h>
++#include <linux/mutex.h>
++#include <linux/workqueue.h>
++#include "firmware.h"
++#include "greybus.h"
++
++/* Estimated minimum buffer size, actual size can be smaller than this */
++#define MIN_FETCH_SIZE 512
++/* Timeout, in jiffies, within which fetch or release firmware must be called */
++#define NEXT_REQ_TIMEOUT_J msecs_to_jiffies(1000)
++
++struct fw_request {
++ u8 firmware_id;
++ bool disabled;
++ bool timedout;
++ char name[FW_NAME_SIZE];
++ const struct firmware *fw;
++ struct list_head node;
++
++ struct delayed_work dwork;
++ /* Timeout, in jiffies, within which the firmware shall download */
++ unsigned long release_timeout_j;
++ struct kref kref;
++ struct fw_download *fw_download;
++};
++
++struct fw_download {
++ struct device *parent;
++ struct gb_connection *connection;
++ struct list_head fw_requests;
++ struct ida id_map;
++ struct mutex mutex;
++};
++
++static void fw_req_release(struct kref *kref)
++{
++ struct fw_request *fw_req = container_of(kref, struct fw_request, kref);
++
++ dev_dbg(fw_req->fw_download->parent, "firmware %s released\n",
++ fw_req->name);
++
++ release_firmware(fw_req->fw);
++
++ /*
++ * The request timed out and the module may send a fetch-fw or
++ * release-fw request later. Lets block the id we allocated for this
++ * request, so that the AP doesn't refer to a later fw-request (with
++ * same firmware_id) for the old timedout fw-request.
++ *
++ * NOTE:
++ *
++ * This also means that after 255 timeouts we will fail to service new
++ * firmware downloads. But what else can we do in that case anyway? Lets
++ * just hope that it never happens.
++ */
++ if (!fw_req->timedout)
++ ida_simple_remove(&fw_req->fw_download->id_map,
++ fw_req->firmware_id);
++
++ kfree(fw_req);
++}
++
++/*
++ * Incoming requests are serialized for a connection, and the only race possible
++ * is between the timeout handler freeing this and an incoming request.
++ *
++ * The operations on the fw-request list are protected by the mutex and
++ * get_fw_req() increments the reference count before returning a fw_req pointer
++ * to the users.
++ *
++ * free_firmware() also takes the mutex while removing an entry from the list,
++ * it guarantees that every user of fw_req has taken a kref-reference by now and
++ * we wouldn't have any new users.
++ *
++ * Once the last user drops the reference, the fw_req structure is freed.
++ */
++static void put_fw_req(struct fw_request *fw_req)
++{
++ kref_put(&fw_req->kref, fw_req_release);
++}
++
++/* Caller must call put_fw_req() after using struct fw_request */
++static struct fw_request *get_fw_req(struct fw_download *fw_download,
++ u8 firmware_id)
++{
++ struct fw_request *fw_req;
++
++ mutex_lock(&fw_download->mutex);
++
++ list_for_each_entry(fw_req, &fw_download->fw_requests, node) {
++ if (fw_req->firmware_id == firmware_id) {
++ kref_get(&fw_req->kref);
++ goto unlock;
++ }
++ }
++
++ fw_req = NULL;
++
++unlock:
++ mutex_unlock(&fw_download->mutex);
++
++ return fw_req;
++}
++
++static void free_firmware(struct fw_download *fw_download,
++ struct fw_request *fw_req)
++{
++ /* Already disabled from timeout handlers */
++ if (fw_req->disabled)
++ return;
++
++ mutex_lock(&fw_download->mutex);
++ list_del(&fw_req->node);
++ mutex_unlock(&fw_download->mutex);
++
++ fw_req->disabled = true;
++ put_fw_req(fw_req);
++}
++
++static void fw_request_timedout(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct fw_request *fw_req = container_of(dwork, struct fw_request, dwork);
++ struct fw_download *fw_download = fw_req->fw_download;
++
++ dev_err(fw_download->parent,
++ "Timed out waiting for fetch / release firmware requests: %u\n",
++ fw_req->firmware_id);
++
++ fw_req->timedout = true;
++ free_firmware(fw_download, fw_req);
++}
++
++static int exceeds_release_timeout(struct fw_request *fw_req)
++{
++ struct fw_download *fw_download = fw_req->fw_download;
++
++ if (time_before(jiffies, fw_req->release_timeout_j))
++ return 0;
++
++ dev_err(fw_download->parent,
++ "Firmware download didn't finish in time, abort: %d\n",
++ fw_req->firmware_id);
++
++ fw_req->timedout = true;
++ free_firmware(fw_download, fw_req);
++
++ return -ETIMEDOUT;
++}
++
++/* This returns path of the firmware blob on the disk */
++static struct fw_request *find_firmware(struct fw_download *fw_download,
++ const char *tag)
++{
++ struct gb_interface *intf = fw_download->connection->bundle->intf;
++ struct fw_request *fw_req;
++ int ret, req_count;
++
++ fw_req = kzalloc(sizeof(*fw_req), GFP_KERNEL);
++ if (!fw_req)
++ return ERR_PTR(-ENOMEM);
++
++ /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
++ ret = ida_simple_get(&fw_download->id_map, 1, 256, GFP_KERNEL);
++ if (ret < 0) {
++ dev_err(fw_download->parent,
++ "failed to allocate firmware id (%d)\n", ret);
++ goto err_free_req;
++ }
++ fw_req->firmware_id = ret;
++
++ snprintf(fw_req->name, sizeof(fw_req->name),
++ FW_NAME_PREFIX "%08x_%08x_%08x_%08x_%s.tftf",
++ intf->ddbl1_manufacturer_id, intf->ddbl1_product_id,
++ intf->vendor_id, intf->product_id, tag);
++
++ dev_info(fw_download->parent, "Requested firmware package '%s'\n",
++ fw_req->name);
++
++ ret = request_firmware(&fw_req->fw, fw_req->name, fw_download->parent);
++ if (ret) {
++ dev_err(fw_download->parent,
++ "firmware request failed for %s (%d)\n", fw_req->name,
++ ret);
++ goto err_free_id;
++ }
++
++ fw_req->fw_download = fw_download;
++ kref_init(&fw_req->kref);
++
++ mutex_lock(&fw_download->mutex);
++ list_add(&fw_req->node, &fw_download->fw_requests);
++ mutex_unlock(&fw_download->mutex);
++
++ /* Timeout, in jiffies, within which firmware should get loaded */
++ req_count = DIV_ROUND_UP(fw_req->fw->size, MIN_FETCH_SIZE);
++ fw_req->release_timeout_j = jiffies + req_count * NEXT_REQ_TIMEOUT_J;
++
++ INIT_DELAYED_WORK(&fw_req->dwork, fw_request_timedout);
++ schedule_delayed_work(&fw_req->dwork, NEXT_REQ_TIMEOUT_J);
++
++ return fw_req;
++
++err_free_id:
++ ida_simple_remove(&fw_download->id_map, fw_req->firmware_id);
++err_free_req:
++ kfree(fw_req);
++
++ return ERR_PTR(ret);
++}
++
++static int fw_download_find_firmware(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct fw_download *fw_download = gb_connection_get_data(connection);
++ struct gb_fw_download_find_firmware_request *request;
++ struct gb_fw_download_find_firmware_response *response;
++ struct fw_request *fw_req;
++ const char *tag;
++
++ if (op->request->payload_size != sizeof(*request)) {
++ dev_err(fw_download->parent,
++ "illegal size of find firmware request (%zu != %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++ tag = (const char *)request->firmware_tag;
++
++ /* firmware_tag must be null-terminated */
++ if (strnlen(tag, GB_FIRMWARE_TAG_MAX_SIZE) == GB_FIRMWARE_TAG_MAX_SIZE) {
++ dev_err(fw_download->parent,
++ "firmware-tag is not null-terminated\n");
++ return -EINVAL;
++ }
++
++ fw_req = find_firmware(fw_download, tag);
++ if (IS_ERR(fw_req))
++ return PTR_ERR(fw_req);
++
++ if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL)) {
++ dev_err(fw_download->parent, "error allocating response\n");
++ free_firmware(fw_download, fw_req);
++ return -ENOMEM;
++ }
++
++ response = op->response->payload;
++ response->firmware_id = fw_req->firmware_id;
++ response->size = cpu_to_le32(fw_req->fw->size);
++
++ dev_dbg(fw_download->parent,
++ "firmware size is %zu bytes\n", fw_req->fw->size);
++
++ return 0;
++}
++
++static int fw_download_fetch_firmware(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct fw_download *fw_download = gb_connection_get_data(connection);
++ struct gb_fw_download_fetch_firmware_request *request;
++ struct gb_fw_download_fetch_firmware_response *response;
++ struct fw_request *fw_req;
++ const struct firmware *fw;
++ unsigned int offset, size;
++ u8 firmware_id;
++ int ret = 0;
++
++ if (op->request->payload_size != sizeof(*request)) {
++ dev_err(fw_download->parent,
++ "Illegal size of fetch firmware request (%zu %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++ offset = le32_to_cpu(request->offset);
++ size = le32_to_cpu(request->size);
++ firmware_id = request->firmware_id;
++
++ fw_req = get_fw_req(fw_download, firmware_id);
++ if (!fw_req) {
++ dev_err(fw_download->parent,
++ "firmware not available for id: %02u\n", firmware_id);
++ return -EINVAL;
++ }
++
++ /* Make sure work handler isn't running in parallel */
++ cancel_delayed_work_sync(&fw_req->dwork);
++
++ /* We timed-out before reaching here ? */
++ if (fw_req->disabled) {
++ ret = -ETIMEDOUT;
++ goto put_fw;
++ }
++
++ /*
++ * Firmware download must finish within a limited time interval. If it
++ * doesn't, then we might have a buggy Module on the other side. Abort
++ * download.
++ */
++ ret = exceeds_release_timeout(fw_req);
++ if (ret)
++ goto put_fw;
++
++ fw = fw_req->fw;
++
++ if (offset >= fw->size || size > fw->size - offset) {
++ dev_err(fw_download->parent,
++ "bad fetch firmware request (offs = %u, size = %u)\n",
++ offset, size);
++ ret = -EINVAL;
++ goto put_fw;
++ }
++
++ if (!gb_operation_response_alloc(op, sizeof(*response) + size,
++ GFP_KERNEL)) {
++ dev_err(fw_download->parent,
++ "error allocating fetch firmware response\n");
++ ret = -ENOMEM;
++ goto put_fw;
++ }
++
++ response = op->response->payload;
++ memcpy(response->data, fw->data + offset, size);
++
++ dev_dbg(fw_download->parent,
++ "responding with firmware (offs = %u, size = %u)\n", offset,
++ size);
++
++ /* Refresh timeout */
++ schedule_delayed_work(&fw_req->dwork, NEXT_REQ_TIMEOUT_J);
++
++put_fw:
++ put_fw_req(fw_req);
++
++ return ret;
++}
++
++static int fw_download_release_firmware(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct fw_download *fw_download = gb_connection_get_data(connection);
++ struct gb_fw_download_release_firmware_request *request;
++ struct fw_request *fw_req;
++ u8 firmware_id;
++
++ if (op->request->payload_size != sizeof(*request)) {
++ dev_err(fw_download->parent,
++ "Illegal size of release firmware request (%zu %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++ firmware_id = request->firmware_id;
++
++ fw_req = get_fw_req(fw_download, firmware_id);
++ if (!fw_req) {
++ dev_err(fw_download->parent,
++ "firmware not available for id: %02u\n", firmware_id);
++ return -EINVAL;
++ }
++
++ cancel_delayed_work_sync(&fw_req->dwork);
++
++ free_firmware(fw_download, fw_req);
++ put_fw_req(fw_req);
++
++ dev_dbg(fw_download->parent, "release firmware\n");
++
++ return 0;
++}
++
++int gb_fw_download_request_handler(struct gb_operation *op)
++{
++ u8 type = op->type;
++
++ switch (type) {
++ case GB_FW_DOWNLOAD_TYPE_FIND_FIRMWARE:
++ return fw_download_find_firmware(op);
++ case GB_FW_DOWNLOAD_TYPE_FETCH_FIRMWARE:
++ return fw_download_fetch_firmware(op);
++ case GB_FW_DOWNLOAD_TYPE_RELEASE_FIRMWARE:
++ return fw_download_release_firmware(op);
++ default:
++ dev_err(&op->connection->bundle->dev,
++ "unsupported request: %u\n", type);
++ return -EINVAL;
++ }
++}
++
++int gb_fw_download_connection_init(struct gb_connection *connection)
++{
++ struct fw_download *fw_download;
++ int ret;
++
++ if (!connection)
++ return 0;
++
++ fw_download = kzalloc(sizeof(*fw_download), GFP_KERNEL);
++ if (!fw_download)
++ return -ENOMEM;
++
++ fw_download->parent = &connection->bundle->dev;
++ INIT_LIST_HEAD(&fw_download->fw_requests);
++ ida_init(&fw_download->id_map);
++ gb_connection_set_data(connection, fw_download);
++ fw_download->connection = connection;
++ mutex_init(&fw_download->mutex);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto err_destroy_id_map;
++
++ return 0;
++
++err_destroy_id_map:
++ ida_destroy(&fw_download->id_map);
++ kfree(fw_download);
++
++ return ret;
++}
++
++void gb_fw_download_connection_exit(struct gb_connection *connection)
++{
++ struct fw_download *fw_download;
++ struct fw_request *fw_req, *tmp;
++
++ if (!connection)
++ return;
++
++ fw_download = gb_connection_get_data(connection);
++ gb_connection_disable(fw_download->connection);
++
++ /*
++ * Make sure we have a reference to the pending requests, before they
++ * are freed from the timeout handler.
++ */
++ mutex_lock(&fw_download->mutex);
++ list_for_each_entry(fw_req, &fw_download->fw_requests, node)
++ kref_get(&fw_req->kref);
++ mutex_unlock(&fw_download->mutex);
++
++ /* Release pending firmware packages */
++ list_for_each_entry_safe(fw_req, tmp, &fw_download->fw_requests, node) {
++ cancel_delayed_work_sync(&fw_req->dwork);
++ free_firmware(fw_download, fw_req);
++ put_fw_req(fw_req);
++ }
++
++ ida_destroy(&fw_download->id_map);
++ kfree(fw_download);
++}
+--- /dev/null
++++ b/drivers/greybus/fw-management.c
+@@ -0,0 +1,721 @@
++/*
++ * Greybus Firmware Management Protocol Driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/cdev.h>
++#include <linux/completion.h>
++#include <linux/firmware.h>
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/ioctl.h>
++#include <linux/uaccess.h>
++
++#include "firmware.h"
++#include "greybus_firmware.h"
++#include "greybus.h"
++
++#define FW_MGMT_TIMEOUT_MS 1000
++
++struct fw_mgmt {
++ struct device *parent;
++ struct gb_connection *connection;
++ struct kref kref;
++ struct list_head node;
++
++ /* Common id-map for interface and backend firmware requests */
++ struct ida id_map;
++ struct mutex mutex;
++ struct completion completion;
++ struct cdev cdev;
++ struct device *class_device;
++ dev_t dev_num;
++ unsigned int timeout_jiffies;
++ bool disabled; /* connection getting disabled */
++
++ /* Interface Firmware specific fields */
++ bool mode_switch_started;
++ bool intf_fw_loaded;
++ u8 intf_fw_request_id;
++ u8 intf_fw_status;
++ u16 intf_fw_major;
++ u16 intf_fw_minor;
++
++ /* Backend Firmware specific fields */
++ u8 backend_fw_request_id;
++ u8 backend_fw_status;
++};
++
++/*
++ * Number of minor devices this driver supports.
++ * There will be exactly one required per Interface.
++ */
++#define NUM_MINORS U8_MAX
++
++static struct class *fw_mgmt_class;
++static dev_t fw_mgmt_dev_num;
++static DEFINE_IDA(fw_mgmt_minors_map);
++static LIST_HEAD(fw_mgmt_list);
++static DEFINE_MUTEX(list_mutex);
++
++static void fw_mgmt_kref_release(struct kref *kref)
++{
++ struct fw_mgmt *fw_mgmt = container_of(kref, struct fw_mgmt, kref);
++
++ ida_destroy(&fw_mgmt->id_map);
++ kfree(fw_mgmt);
++}
++
++/*
++ * All users of fw_mgmt take a reference (from within list_mutex lock), before
++ * they get a pointer to play with. And the structure will be freed only after
++ * the last user has put the reference to it.
++ */
++static void put_fw_mgmt(struct fw_mgmt *fw_mgmt)
++{
++ kref_put(&fw_mgmt->kref, fw_mgmt_kref_release);
++}
++
++/* Caller must call put_fw_mgmt() after using struct fw_mgmt */
++static struct fw_mgmt *get_fw_mgmt(struct cdev *cdev)
++{
++ struct fw_mgmt *fw_mgmt;
++
++ mutex_lock(&list_mutex);
++
++ list_for_each_entry(fw_mgmt, &fw_mgmt_list, node) {
++ if (&fw_mgmt->cdev == cdev) {
++ kref_get(&fw_mgmt->kref);
++ goto unlock;
++ }
++ }
++
++ fw_mgmt = NULL;
++
++unlock:
++ mutex_unlock(&list_mutex);
++
++ return fw_mgmt;
++}
++
++static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt,
++ struct fw_mgmt_ioc_get_intf_version *fw_info)
++{
++ struct gb_connection *connection = fw_mgmt->connection;
++ struct gb_fw_mgmt_interface_fw_version_response response;
++ int ret;
++
++ ret = gb_operation_sync(connection,
++ GB_FW_MGMT_TYPE_INTERFACE_FW_VERSION, NULL, 0,
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(fw_mgmt->parent,
++ "failed to get interface firmware version (%d)\n", ret);
++ return ret;
++ }
++
++ fw_info->major = le16_to_cpu(response.major);
++ fw_info->minor = le16_to_cpu(response.minor);
++
++ strncpy(fw_info->firmware_tag, response.firmware_tag,
++ GB_FIRMWARE_TAG_MAX_SIZE);
++
++ /*
++ * The firmware-tag should be NULL terminated, otherwise throw error but
++ * don't fail.
++ */
++ if (fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
++ dev_err(fw_mgmt->parent,
++ "fw-version: firmware-tag is not NULL terminated\n");
++ fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] = '\0';
++ }
++
++ return 0;
++}
++
++static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
++ u8 load_method, const char *tag)
++{
++ struct gb_fw_mgmt_load_and_validate_fw_request request;
++ int ret;
++
++ if (load_method != GB_FW_LOAD_METHOD_UNIPRO &&
++ load_method != GB_FW_LOAD_METHOD_INTERNAL) {
++ dev_err(fw_mgmt->parent,
++ "invalid load-method (%d)\n", load_method);
++ return -EINVAL;
++ }
++
++ request.load_method = load_method;
++ strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
++
++ /*
++ * The firmware-tag should be NULL terminated, otherwise throw error and
++ * fail.
++ */
++ if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
++ dev_err(fw_mgmt->parent, "load-and-validate: firmware-tag is not NULL terminated\n");
++ return -EINVAL;
++ }
++
++ /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
++ ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
++ if (ret < 0) {
++ dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
++ ret);
++ return ret;
++ }
++
++ fw_mgmt->intf_fw_request_id = ret;
++ fw_mgmt->intf_fw_loaded = false;
++ request.request_id = ret;
++
++ ret = gb_operation_sync(fw_mgmt->connection,
++ GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW, &request,
++ sizeof(request), NULL, 0);
++ if (ret) {
++ ida_simple_remove(&fw_mgmt->id_map,
++ fw_mgmt->intf_fw_request_id);
++ fw_mgmt->intf_fw_request_id = 0;
++ dev_err(fw_mgmt->parent,
++ "load and validate firmware request failed (%d)\n",
++ ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
++ struct gb_fw_mgmt_loaded_fw_request *request;
++
++ /* No pending load and validate request ? */
++ if (!fw_mgmt->intf_fw_request_id) {
++ dev_err(fw_mgmt->parent,
++ "unexpected firmware loaded request received\n");
++ return -ENODEV;
++ }
++
++ if (op->request->payload_size != sizeof(*request)) {
++ dev_err(fw_mgmt->parent, "illegal size of firmware loaded request (%zu != %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ /* Invalid request-id ? */
++ if (request->request_id != fw_mgmt->intf_fw_request_id) {
++ dev_err(fw_mgmt->parent, "invalid request id for firmware loaded request (%02u != %02u)\n",
++ fw_mgmt->intf_fw_request_id, request->request_id);
++ return -ENODEV;
++ }
++
++ ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
++ fw_mgmt->intf_fw_request_id = 0;
++ fw_mgmt->intf_fw_status = request->status;
++ fw_mgmt->intf_fw_major = le16_to_cpu(request->major);
++ fw_mgmt->intf_fw_minor = le16_to_cpu(request->minor);
++
++ if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_FAILED)
++ dev_err(fw_mgmt->parent,
++ "failed to load interface firmware, status:%02x\n",
++ fw_mgmt->intf_fw_status);
++ else if (fw_mgmt->intf_fw_status == GB_FW_LOAD_STATUS_VALIDATION_FAILED)
++ dev_err(fw_mgmt->parent,
++ "failed to validate interface firmware, status:%02x\n",
++ fw_mgmt->intf_fw_status);
++ else
++ fw_mgmt->intf_fw_loaded = true;
++
++ complete(&fw_mgmt->completion);
++
++ return 0;
++}
++
++static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt,
++ struct fw_mgmt_ioc_get_backend_version *fw_info)
++{
++ struct gb_connection *connection = fw_mgmt->connection;
++ struct gb_fw_mgmt_backend_fw_version_request request;
++ struct gb_fw_mgmt_backend_fw_version_response response;
++ int ret;
++
++ strncpy(request.firmware_tag, fw_info->firmware_tag,
++ GB_FIRMWARE_TAG_MAX_SIZE);
++
++ /*
++ * The firmware-tag should be NULL terminated, otherwise throw error and
++ * fail.
++ */
++ if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
++ dev_err(fw_mgmt->parent, "backend-version: firmware-tag is not NULL terminated\n");
++ return -EINVAL;
++ }
++
++ ret = gb_operation_sync(connection,
++ GB_FW_MGMT_TYPE_BACKEND_FW_VERSION, &request,
++ sizeof(request), &response, sizeof(response));
++ if (ret) {
++ dev_err(fw_mgmt->parent, "failed to get version of %s backend firmware (%d)\n",
++ fw_info->firmware_tag, ret);
++ return ret;
++ }
++
++ fw_info->status = response.status;
++
++ /* Reset version as that should be non-zero only for success case */
++ fw_info->major = 0;
++ fw_info->minor = 0;
++
++ switch (fw_info->status) {
++ case GB_FW_BACKEND_VERSION_STATUS_SUCCESS:
++ fw_info->major = le16_to_cpu(response.major);
++ fw_info->minor = le16_to_cpu(response.minor);
++ break;
++ case GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE:
++ case GB_FW_BACKEND_VERSION_STATUS_RETRY:
++ break;
++ case GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED:
++ dev_err(fw_mgmt->parent,
++ "Firmware with tag %s is not supported by Interface\n",
++ fw_info->firmware_tag);
++ break;
++ default:
++ dev_err(fw_mgmt->parent, "Invalid status received: %u\n",
++ fw_info->status);
++ }
++
++ return 0;
++}
++
++static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
++ char *tag)
++{
++ struct gb_fw_mgmt_backend_fw_update_request request;
++ int ret;
++
++ strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE);
++
++ /*
++ * The firmware-tag should be NULL terminated, otherwise throw error and
++ * fail.
++ */
++ if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
++ dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n");
++ return -EINVAL;
++ }
++
++ /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
++ ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
++ if (ret < 0) {
++ dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
++ ret);
++ return ret;
++ }
++
++ fw_mgmt->backend_fw_request_id = ret;
++ request.request_id = ret;
++
++ ret = gb_operation_sync(fw_mgmt->connection,
++ GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE, &request,
++ sizeof(request), NULL, 0);
++ if (ret) {
++ ida_simple_remove(&fw_mgmt->id_map,
++ fw_mgmt->backend_fw_request_id);
++ fw_mgmt->backend_fw_request_id = 0;
++ dev_err(fw_mgmt->parent,
++ "backend %s firmware update request failed (%d)\n", tag,
++ ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int fw_mgmt_backend_fw_updated_operation(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct fw_mgmt *fw_mgmt = gb_connection_get_data(connection);
++ struct gb_fw_mgmt_backend_fw_updated_request *request;
++
++ /* No pending load and validate request ? */
++ if (!fw_mgmt->backend_fw_request_id) {
++ dev_err(fw_mgmt->parent, "unexpected backend firmware updated request received\n");
++ return -ENODEV;
++ }
++
++ if (op->request->payload_size != sizeof(*request)) {
++ dev_err(fw_mgmt->parent, "illegal size of backend firmware updated request (%zu != %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ /* Invalid request-id ? */
++ if (request->request_id != fw_mgmt->backend_fw_request_id) {
++ dev_err(fw_mgmt->parent, "invalid request id for backend firmware updated request (%02u != %02u)\n",
++ fw_mgmt->backend_fw_request_id, request->request_id);
++ return -ENODEV;
++ }
++
++ ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
++ fw_mgmt->backend_fw_request_id = 0;
++ fw_mgmt->backend_fw_status = request->status;
++
++ if ((fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_SUCCESS) &&
++ (fw_mgmt->backend_fw_status != GB_FW_BACKEND_FW_STATUS_RETRY))
++ dev_err(fw_mgmt->parent,
++ "failed to load backend firmware: %02x\n",
++ fw_mgmt->backend_fw_status);
++
++ complete(&fw_mgmt->completion);
++
++ return 0;
++}
++
++/* Char device fops */
++
++static int fw_mgmt_open(struct inode *inode, struct file *file)
++{
++ struct fw_mgmt *fw_mgmt = get_fw_mgmt(inode->i_cdev);
++
++ /* fw_mgmt structure can't get freed until file descriptor is closed */
++ if (fw_mgmt) {
++ file->private_data = fw_mgmt;
++ return 0;
++ }
++
++ return -ENODEV;
++}
++
++static int fw_mgmt_release(struct inode *inode, struct file *file)
++{
++ struct fw_mgmt *fw_mgmt = file->private_data;
++
++ put_fw_mgmt(fw_mgmt);
++ return 0;
++}
++
++static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd,
++ void __user *buf)
++{
++ struct fw_mgmt_ioc_get_intf_version intf_fw_info;
++ struct fw_mgmt_ioc_get_backend_version backend_fw_info;
++ struct fw_mgmt_ioc_intf_load_and_validate intf_load;
++ struct fw_mgmt_ioc_backend_fw_update backend_update;
++ unsigned int timeout;
++ int ret;
++
++ /* Reject any operations after mode-switch has started */
++ if (fw_mgmt->mode_switch_started)
++ return -EBUSY;
++
++ switch (cmd) {
++ case FW_MGMT_IOC_GET_INTF_FW:
++ ret = fw_mgmt_interface_fw_version_operation(fw_mgmt,
++ &intf_fw_info);
++ if (ret)
++ return ret;
++
++ if (copy_to_user(buf, &intf_fw_info, sizeof(intf_fw_info)))
++ return -EFAULT;
++
++ return 0;
++ case FW_MGMT_IOC_GET_BACKEND_FW:
++ if (copy_from_user(&backend_fw_info, buf,
++ sizeof(backend_fw_info)))
++ return -EFAULT;
++
++ ret = fw_mgmt_backend_fw_version_operation(fw_mgmt,
++ &backend_fw_info);
++ if (ret)
++ return ret;
++
++ if (copy_to_user(buf, &backend_fw_info,
++ sizeof(backend_fw_info)))
++ return -EFAULT;
++
++ return 0;
++ case FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE:
++ if (copy_from_user(&intf_load, buf, sizeof(intf_load)))
++ return -EFAULT;
++
++ ret = fw_mgmt_load_and_validate_operation(fw_mgmt,
++ intf_load.load_method, intf_load.firmware_tag);
++ if (ret)
++ return ret;
++
++ if (!wait_for_completion_timeout(&fw_mgmt->completion,
++ fw_mgmt->timeout_jiffies)) {
++ dev_err(fw_mgmt->parent, "timed out waiting for firmware load and validation to finish\n");
++ return -ETIMEDOUT;
++ }
++
++ intf_load.status = fw_mgmt->intf_fw_status;
++ intf_load.major = fw_mgmt->intf_fw_major;
++ intf_load.minor = fw_mgmt->intf_fw_minor;
++
++ if (copy_to_user(buf, &intf_load, sizeof(intf_load)))
++ return -EFAULT;
++
++ return 0;
++ case FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE:
++ if (copy_from_user(&backend_update, buf,
++ sizeof(backend_update)))
++ return -EFAULT;
++
++ ret = fw_mgmt_backend_fw_update_operation(fw_mgmt,
++ backend_update.firmware_tag);
++ if (ret)
++ return ret;
++
++ if (!wait_for_completion_timeout(&fw_mgmt->completion,
++ fw_mgmt->timeout_jiffies)) {
++ dev_err(fw_mgmt->parent, "timed out waiting for backend firmware update to finish\n");
++ return -ETIMEDOUT;
++ }
++
++ backend_update.status = fw_mgmt->backend_fw_status;
++
++ if (copy_to_user(buf, &backend_update, sizeof(backend_update)))
++ return -EFAULT;
++
++ return 0;
++ case FW_MGMT_IOC_SET_TIMEOUT_MS:
++ if (get_user(timeout, (unsigned int __user *)buf))
++ return -EFAULT;
++
++ if (!timeout) {
++ dev_err(fw_mgmt->parent, "timeout can't be zero\n");
++ return -EINVAL;
++ }
++
++ fw_mgmt->timeout_jiffies = msecs_to_jiffies(timeout);
++
++ return 0;
++ case FW_MGMT_IOC_MODE_SWITCH:
++ if (!fw_mgmt->intf_fw_loaded) {
++ dev_err(fw_mgmt->parent,
++ "Firmware not loaded for mode-switch\n");
++ return -EPERM;
++ }
++
++ /*
++ * Disallow new ioctls as the fw-core bundle driver is going to
++ * get disconnected soon and the character device will get
++ * removed.
++ */
++ fw_mgmt->mode_switch_started = true;
++
++ ret = gb_interface_request_mode_switch(fw_mgmt->connection->intf);
++ if (ret) {
++ dev_err(fw_mgmt->parent, "Mode-switch failed: %d\n",
++ ret);
++ fw_mgmt->mode_switch_started = false;
++ return ret;
++ }
++
++ return 0;
++ default:
++ return -ENOTTY;
++ }
++}
++
++static long fw_mgmt_ioctl_unlocked(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ struct fw_mgmt *fw_mgmt = file->private_data;
++ struct gb_bundle *bundle = fw_mgmt->connection->bundle;
++ int ret = -ENODEV;
++
++ /*
++ * Serialize ioctls.
++ *
++ * We don't want the user to do few operations in parallel. For example,
++ * updating Interface firmware in parallel for the same Interface. There
++ * is no need to do things in parallel for speed and we can avoid having
++ * complicated code for now.
++ *
++ * This is also used to protect ->disabled, which is used to check if
++ * the connection is getting disconnected, so that we don't start any
++ * new operations.
++ */
++ mutex_lock(&fw_mgmt->mutex);
++ if (!fw_mgmt->disabled) {
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (!ret) {
++ ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg);
++ gb_pm_runtime_put_autosuspend(bundle);
++ }
++ }
++ mutex_unlock(&fw_mgmt->mutex);
++
++ return ret;
++}
++
++static const struct file_operations fw_mgmt_fops = {
++ .owner = THIS_MODULE,
++ .open = fw_mgmt_open,
++ .release = fw_mgmt_release,
++ .unlocked_ioctl = fw_mgmt_ioctl_unlocked,
++};
++
++int gb_fw_mgmt_request_handler(struct gb_operation *op)
++{
++ u8 type = op->type;
++
++ switch (type) {
++ case GB_FW_MGMT_TYPE_LOADED_FW:
++ return fw_mgmt_interface_fw_loaded_operation(op);
++ case GB_FW_MGMT_TYPE_BACKEND_FW_UPDATED:
++ return fw_mgmt_backend_fw_updated_operation(op);
++ default:
++ dev_err(&op->connection->bundle->dev,
++ "unsupported request: %u\n", type);
++ return -EINVAL;
++ }
++}
++
++int gb_fw_mgmt_connection_init(struct gb_connection *connection)
++{
++ struct fw_mgmt *fw_mgmt;
++ int ret, minor;
++
++ if (!connection)
++ return 0;
++
++ fw_mgmt = kzalloc(sizeof(*fw_mgmt), GFP_KERNEL);
++ if (!fw_mgmt)
++ return -ENOMEM;
++
++ fw_mgmt->parent = &connection->bundle->dev;
++ fw_mgmt->timeout_jiffies = msecs_to_jiffies(FW_MGMT_TIMEOUT_MS);
++ fw_mgmt->connection = connection;
++
++ gb_connection_set_data(connection, fw_mgmt);
++ init_completion(&fw_mgmt->completion);
++ ida_init(&fw_mgmt->id_map);
++ mutex_init(&fw_mgmt->mutex);
++ kref_init(&fw_mgmt->kref);
++
++ mutex_lock(&list_mutex);
++ list_add(&fw_mgmt->node, &fw_mgmt_list);
++ mutex_unlock(&list_mutex);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto err_list_del;
++
++ minor = ida_simple_get(&fw_mgmt_minors_map, 0, NUM_MINORS, GFP_KERNEL);
++ if (minor < 0) {
++ ret = minor;
++ goto err_connection_disable;
++ }
++
++ /* Add a char device to allow userspace to interact with fw-mgmt */
++ fw_mgmt->dev_num = MKDEV(MAJOR(fw_mgmt_dev_num), minor);
++ cdev_init(&fw_mgmt->cdev, &fw_mgmt_fops);
++
++ ret = cdev_add(&fw_mgmt->cdev, fw_mgmt->dev_num, 1);
++ if (ret)
++ goto err_remove_ida;
++
++ /* Add a soft link to the previously added char-dev within the bundle */
++ fw_mgmt->class_device = device_create(fw_mgmt_class, fw_mgmt->parent,
++ fw_mgmt->dev_num, NULL,
++ "gb-fw-mgmt-%d", minor);
++ if (IS_ERR(fw_mgmt->class_device)) {
++ ret = PTR_ERR(fw_mgmt->class_device);
++ goto err_del_cdev;
++ }
++
++ return 0;
++
++err_del_cdev:
++ cdev_del(&fw_mgmt->cdev);
++err_remove_ida:
++ ida_simple_remove(&fw_mgmt_minors_map, minor);
++err_connection_disable:
++ gb_connection_disable(connection);
++err_list_del:
++ mutex_lock(&list_mutex);
++ list_del(&fw_mgmt->node);
++ mutex_unlock(&list_mutex);
++
++ put_fw_mgmt(fw_mgmt);
++
++ return ret;
++}
++
++void gb_fw_mgmt_connection_exit(struct gb_connection *connection)
++{
++ struct fw_mgmt *fw_mgmt;
++
++ if (!connection)
++ return;
++
++ fw_mgmt = gb_connection_get_data(connection);
++
++ device_destroy(fw_mgmt_class, fw_mgmt->dev_num);
++ cdev_del(&fw_mgmt->cdev);
++ ida_simple_remove(&fw_mgmt_minors_map, MINOR(fw_mgmt->dev_num));
++
++ /*
++ * Disallow any new ioctl operations on the char device and wait for
++ * existing ones to finish.
++ */
++ mutex_lock(&fw_mgmt->mutex);
++ fw_mgmt->disabled = true;
++ mutex_unlock(&fw_mgmt->mutex);
++
++ /* All pending greybus operations should have finished by now */
++ gb_connection_disable(fw_mgmt->connection);
++
++ /* Disallow new users to get access to the fw_mgmt structure */
++ mutex_lock(&list_mutex);
++ list_del(&fw_mgmt->node);
++ mutex_unlock(&list_mutex);
++
++ /*
++ * All current users of fw_mgmt would have taken a reference to it by
++ * now, we can drop our reference and wait the last user will get
++ * fw_mgmt freed.
++ */
++ put_fw_mgmt(fw_mgmt);
++}
++
++int fw_mgmt_init(void)
++{
++ int ret;
++
++ fw_mgmt_class = class_create(THIS_MODULE, "gb_fw_mgmt");
++ if (IS_ERR(fw_mgmt_class))
++ return PTR_ERR(fw_mgmt_class);
++
++ ret = alloc_chrdev_region(&fw_mgmt_dev_num, 0, NUM_MINORS,
++ "gb_fw_mgmt");
++ if (ret)
++ goto err_remove_class;
++
++ return 0;
++
++err_remove_class:
++ class_destroy(fw_mgmt_class);
++ return ret;
++}
++
++void fw_mgmt_exit(void)
++{
++ unregister_chrdev_region(fw_mgmt_dev_num, NUM_MINORS);
++ class_destroy(fw_mgmt_class);
++ ida_destroy(&fw_mgmt_minors_map);
++}
+--- /dev/null
++++ b/drivers/greybus/greybus_firmware.h
+@@ -0,0 +1,120 @@
++/*
++ * Greybus Firmware Management User Header
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2016 Google Inc. All rights reserved.
++ * Copyright(c) 2016 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __GREYBUS_FIRMWARE_USER_H
++#define __GREYBUS_FIRMWARE_USER_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#define GB_FIRMWARE_U_TAG_MAX_SIZE 10
++
++#define GB_FW_U_LOAD_METHOD_UNIPRO 0x01
++#define GB_FW_U_LOAD_METHOD_INTERNAL 0x02
++
++#define GB_FW_U_LOAD_STATUS_FAILED 0x00
++#define GB_FW_U_LOAD_STATUS_UNVALIDATED 0x01
++#define GB_FW_U_LOAD_STATUS_VALIDATED 0x02
++#define GB_FW_U_LOAD_STATUS_VALIDATION_FAILED 0x03
++
++#define GB_FW_U_BACKEND_FW_STATUS_SUCCESS 0x01
++#define GB_FW_U_BACKEND_FW_STATUS_FAIL_FIND 0x02
++#define GB_FW_U_BACKEND_FW_STATUS_FAIL_FETCH 0x03
++#define GB_FW_U_BACKEND_FW_STATUS_FAIL_WRITE 0x04
++#define GB_FW_U_BACKEND_FW_STATUS_INT 0x05
++#define GB_FW_U_BACKEND_FW_STATUS_RETRY 0x06
++#define GB_FW_U_BACKEND_FW_STATUS_NOT_SUPPORTED 0x07
++
++#define GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS 0x01
++#define GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE 0x02
++#define GB_FW_U_BACKEND_VERSION_STATUS_NOT_SUPPORTED 0x03
++#define GB_FW_U_BACKEND_VERSION_STATUS_RETRY 0x04
++#define GB_FW_U_BACKEND_VERSION_STATUS_FAIL_INT 0x05
++
++/* IOCTL support */
++struct fw_mgmt_ioc_get_intf_version {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u16 major;
++ __u16 minor;
++} __attribute__ ((__packed__));
++
++struct fw_mgmt_ioc_get_backend_version {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u16 major;
++ __u16 minor;
++ __u8 status;
++} __attribute__ ((__packed__));
++
++struct fw_mgmt_ioc_intf_load_and_validate {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u8 load_method;
++ __u8 status;
++ __u16 major;
++ __u16 minor;
++} __attribute__ ((__packed__));
++
++struct fw_mgmt_ioc_backend_fw_update {
++ __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
++ __u8 status;
++} __attribute__ ((__packed__));
++
++#define FW_MGMT_IOCTL_BASE 'F'
++#define FW_MGMT_IOC_GET_INTF_FW _IOR(FW_MGMT_IOCTL_BASE, 0, struct fw_mgmt_ioc_get_intf_version)
++#define FW_MGMT_IOC_GET_BACKEND_FW _IOWR(FW_MGMT_IOCTL_BASE, 1, struct fw_mgmt_ioc_get_backend_version)
++#define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate)
++#define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update)
++#define FW_MGMT_IOC_SET_TIMEOUT_MS _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int)
++#define FW_MGMT_IOC_MODE_SWITCH _IO(FW_MGMT_IOCTL_BASE, 5)
++
++#endif /* __GREYBUS_FIRMWARE_USER_H */
++
diff --git a/greybus_gbphy.patch b/greybus_gbphy.patch
new file mode 100644
index 00000000000000..932216ea2e3a65
--- /dev/null
+++ b/greybus_gbphy.patch
@@ -0,0 +1,481 @@
+---
+ drivers/greybus/gbphy.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/gbphy.h | 110 ++++++++++++++
+ 2 files changed, 470 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/gbphy.c
+@@ -0,0 +1,360 @@
++/*
++ * Greybus Bridged-Phy Bus driver
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++#define GB_GBPHY_AUTOSUSPEND_MS 3000
++
++struct gbphy_host {
++ struct gb_bundle *bundle;
++ struct list_head devices;
++};
++
++static DEFINE_IDA(gbphy_id);
++
++static ssize_t protocol_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++
++ return sprintf(buf, "0x%02x\n", gbphy_dev->cport_desc->protocol_id);
++}
++static DEVICE_ATTR_RO(protocol_id);
++
++static struct attribute *gbphy_dev_attrs[] = {
++ &dev_attr_protocol_id.attr,
++ NULL,
++};
++
++ATTRIBUTE_GROUPS(gbphy_dev);
++
++static void gbphy_dev_release(struct device *dev)
++{
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++
++ ida_simple_remove(&gbphy_id, gbphy_dev->id);
++ kfree(gbphy_dev);
++}
++
++#ifdef CONFIG_PM
++static int gb_gbphy_idle(struct device *dev)
++{
++ pm_runtime_mark_last_busy(dev);
++ pm_request_autosuspend(dev);
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops gb_gbphy_pm_ops = {
++ SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
++ pm_generic_runtime_resume,
++ gb_gbphy_idle)
++};
++
++static struct device_type greybus_gbphy_dev_type = {
++ .name = "gbphy_device",
++ .release = gbphy_dev_release,
++ .pm = &gb_gbphy_pm_ops,
++};
++
++static int gbphy_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++ struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc;
++ struct gb_bundle *bundle = gbphy_dev->bundle;
++ struct gb_interface *intf = bundle->intf;
++ struct gb_module *module = intf->module;
++ struct gb_host_device *hd = intf->hd;
++
++ if (add_uevent_var(env, "BUS=%u", hd->bus_id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "MODULE=%u", module->module_id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
++ intf->vendor_id, intf->product_id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "BUNDLE=%u", gbphy_dev->bundle->id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
++ return -ENOMEM;
++ if (add_uevent_var(env, "GBPHY=%u", gbphy_dev->id))
++ return -ENOMEM;
++ if (add_uevent_var(env, "PROTOCOL_ID=%02x", cport_desc->protocol_id))
++ return -ENOMEM;
++
++ return 0;
++}
++
++static const struct gbphy_device_id *
++gbphy_dev_match_id(struct gbphy_device *gbphy_dev, struct gbphy_driver *gbphy_drv)
++{
++ const struct gbphy_device_id *id = gbphy_drv->id_table;
++
++ if (!id)
++ return NULL;
++
++ for (; id->protocol_id; id++)
++ if (id->protocol_id == gbphy_dev->cport_desc->protocol_id)
++ return id;
++
++ return NULL;
++}
++
++static int gbphy_dev_match(struct device *dev, struct device_driver *drv)
++{
++ struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv);
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++ const struct gbphy_device_id *id;
++
++ id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);
++ if (id)
++ return 1;
++
++ return 0;
++}
++
++static int gbphy_dev_probe(struct device *dev)
++{
++ struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++ const struct gbphy_device_id *id;
++ int ret;
++
++ id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);
++ if (!id)
++ return -ENODEV;
++
++ /* for old kernels we need get_sync to resume parent devices */
++ ret = gb_pm_runtime_get_sync(gbphy_dev->bundle);
++ if (ret < 0)
++ return ret;
++
++ pm_runtime_set_autosuspend_delay(dev, GB_GBPHY_AUTOSUSPEND_MS);
++ pm_runtime_use_autosuspend(dev);
++ pm_runtime_get_noresume(dev);
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++
++ /*
++ * Drivers should call put on the gbphy dev before returning
++ * from probe if they support runtime pm.
++ */
++ ret = gbphy_drv->probe(gbphy_dev, id);
++ if (ret) {
++ pm_runtime_disable(dev);
++ pm_runtime_set_suspended(dev);
++ pm_runtime_put_noidle(dev);
++ pm_runtime_dont_use_autosuspend(dev);
++ }
++
++ gb_pm_runtime_put_autosuspend(gbphy_dev->bundle);
++
++ return ret;
++}
++
++static int gbphy_dev_remove(struct device *dev)
++{
++ struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);
++ struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
++
++ gbphy_drv->remove(gbphy_dev);
++
++ pm_runtime_disable(dev);
++ pm_runtime_set_suspended(dev);
++ pm_runtime_put_noidle(dev);
++ pm_runtime_dont_use_autosuspend(dev);
++
++ return 0;
++}
++
++static struct bus_type gbphy_bus_type = {
++ .name = "gbphy",
++ .match = gbphy_dev_match,
++ .probe = gbphy_dev_probe,
++ .remove = gbphy_dev_remove,
++ .uevent = gbphy_dev_uevent,
++};
++
++int gb_gbphy_register_driver(struct gbphy_driver *driver,
++ struct module *owner, const char *mod_name)
++{
++ int retval;
++
++ if (greybus_disabled())
++ return -ENODEV;
++
++ driver->driver.bus = &gbphy_bus_type;
++ driver->driver.name = driver->name;
++ driver->driver.owner = owner;
++ driver->driver.mod_name = mod_name;
++
++ retval = driver_register(&driver->driver);
++ if (retval)
++ return retval;
++
++ pr_info("registered new driver %s\n", driver->name);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_gbphy_register_driver);
++
++void gb_gbphy_deregister_driver(struct gbphy_driver *driver)
++{
++ driver_unregister(&driver->driver);
++}
++EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver);
++
++static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,
++ struct greybus_descriptor_cport *cport_desc)
++{
++ struct gbphy_device *gbphy_dev;
++ int retval;
++ int id;
++
++ id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL);
++ if (id < 0)
++ return ERR_PTR(id);
++
++ gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL);
++ if (!gbphy_dev) {
++ ida_simple_remove(&gbphy_id, id);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ gbphy_dev->id = id;
++ gbphy_dev->bundle = bundle;
++ gbphy_dev->cport_desc = cport_desc;
++ gbphy_dev->dev.parent = &bundle->dev;
++ gbphy_dev->dev.bus = &gbphy_bus_type;
++ gbphy_dev->dev.type = &greybus_gbphy_dev_type;
++ gbphy_dev->dev.groups = gbphy_dev_groups;
++ gbphy_dev->dev.dma_mask = bundle->dev.dma_mask;
++ dev_set_name(&gbphy_dev->dev, "gbphy%d", id);
++
++ retval = device_register(&gbphy_dev->dev);
++ if (retval) {
++ put_device(&gbphy_dev->dev);
++ return ERR_PTR(retval);
++ }
++
++ return gbphy_dev;
++}
++
++static void gb_gbphy_disconnect(struct gb_bundle *bundle)
++{
++ struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle);
++ struct gbphy_device *gbphy_dev, *temp;
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ gb_pm_runtime_get_noresume(bundle);
++
++ list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) {
++ list_del(&gbphy_dev->list);
++ device_unregister(&gbphy_dev->dev);
++ }
++
++ kfree(gbphy_host);
++}
++
++static int gb_gbphy_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct gbphy_host *gbphy_host;
++ struct gbphy_device *gbphy_dev;
++ int i;
++
++ if (bundle->num_cports == 0)
++ return -ENODEV;
++
++ gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL);
++ if (!gbphy_host)
++ return -ENOMEM;
++
++ gbphy_host->bundle = bundle;
++ INIT_LIST_HEAD(&gbphy_host->devices);
++ greybus_set_drvdata(bundle, gbphy_host);
++
++ /*
++ * Create a bunch of children devices, one per cport, and bind the
++ * bridged phy drivers to them.
++ */
++ for (i = 0; i < bundle->num_cports; ++i) {
++ gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]);
++ if (IS_ERR(gbphy_dev)) {
++ gb_gbphy_disconnect(bundle);
++ return PTR_ERR(gbphy_dev);
++ }
++ list_add(&gbphy_dev->list, &gbphy_host->devices);
++ }
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++}
++
++static const struct greybus_bundle_id gb_gbphy_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) },
++ { },
++};
++MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table);
++
++static struct greybus_driver gb_gbphy_driver = {
++ .name = "gbphy",
++ .probe = gb_gbphy_probe,
++ .disconnect = gb_gbphy_disconnect,
++ .id_table = gb_gbphy_id_table,
++};
++
++static int __init gbphy_init(void)
++{
++ int retval;
++
++ retval = bus_register(&gbphy_bus_type);
++ if (retval) {
++ pr_err("gbphy bus register failed (%d)\n", retval);
++ return retval;
++ }
++
++ retval = greybus_register(&gb_gbphy_driver);
++ if (retval) {
++ pr_err("error registering greybus driver\n");
++ goto error_gbphy;
++ }
++
++ return 0;
++
++error_gbphy:
++ bus_unregister(&gbphy_bus_type);
++ ida_destroy(&gbphy_id);
++ return retval;
++}
++module_init(gbphy_init);
++
++static void __exit gbphy_exit(void)
++{
++ greybus_deregister(&gb_gbphy_driver);
++ bus_unregister(&gbphy_bus_type);
++ ida_destroy(&gbphy_id);
++}
++module_exit(gbphy_exit);
++
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/greybus/gbphy.h
+@@ -0,0 +1,110 @@
++/*
++ * Greybus Bridged-Phy Bus driver
++ *
++ * Copyright 2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __GBPHY_H
++#define __GBPHY_H
++
++struct gbphy_device {
++ u32 id;
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_bundle *bundle;
++ struct list_head list;
++ struct device dev;
++};
++#define to_gbphy_dev(d) container_of(d, struct gbphy_device, dev)
++
++static inline void *gb_gbphy_get_data(struct gbphy_device *gdev)
++{
++ return dev_get_drvdata(&gdev->dev);
++}
++
++static inline void gb_gbphy_set_data(struct gbphy_device *gdev, void *data)
++{
++ dev_set_drvdata(&gdev->dev, data);
++}
++
++struct gbphy_device_id {
++ __u8 protocol_id;
++};
++
++#define GBPHY_PROTOCOL(p) \
++ .protocol_id = (p),
++
++struct gbphy_driver {
++ const char *name;
++ int (*probe)(struct gbphy_device *,
++ const struct gbphy_device_id *id);
++ void (*remove)(struct gbphy_device *);
++ const struct gbphy_device_id *id_table;
++
++ struct device_driver driver;
++};
++#define to_gbphy_driver(d) container_of(d, struct gbphy_driver, driver)
++
++int gb_gbphy_register_driver(struct gbphy_driver *driver,
++ struct module *owner, const char *mod_name);
++void gb_gbphy_deregister_driver(struct gbphy_driver *driver);
++
++#define gb_gbphy_register(driver) \
++ gb_gbphy_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
++#define gb_gbphy_deregister(driver) \
++ gb_gbphy_deregister_driver(driver)
++
++/**
++ * module_gbphy_driver() - Helper macro for registering a gbphy driver
++ * @__gbphy_driver: gbphy_driver structure
++ *
++ * Helper macro for gbphy drivers to set up proper module init / exit
++ * functions. Replaces module_init() and module_exit() and keeps people from
++ * printing pointless things to the kernel log when their driver is loaded.
++ */
++#define module_gbphy_driver(__gbphy_driver) \
++ module_driver(__gbphy_driver, gb_gbphy_register, gb_gbphy_deregister)
++
++#ifdef CONFIG_PM
++static inline int gbphy_runtime_get_sync(struct gbphy_device *gbphy_dev)
++{
++ struct device *dev = &gbphy_dev->dev;
++ int ret;
++
++ ret = pm_runtime_get_sync(dev);
++ if (ret < 0) {
++ dev_err(dev, "pm_runtime_get_sync failed: %d\n", ret);
++ pm_runtime_put_noidle(dev);
++ return ret;
++ }
++
++ return 0;
++}
++
++static inline void gbphy_runtime_put_autosuspend(struct gbphy_device *gbphy_dev)
++{
++ struct device *dev = &gbphy_dev->dev;
++
++ pm_runtime_mark_last_busy(dev);
++ pm_runtime_put_autosuspend(dev);
++}
++
++static inline void gbphy_runtime_get_noresume(struct gbphy_device *gbphy_dev)
++{
++ pm_runtime_get_noresume(&gbphy_dev->dev);
++}
++
++static inline void gbphy_runtime_put_noidle(struct gbphy_device *gbphy_dev)
++{
++ pm_runtime_put_noidle(&gbphy_dev->dev);
++}
++#else
++static inline int gbphy_runtime_get_sync(struct gbphy_device *gbphy_dev) { return 0; }
++static inline void gbphy_runtime_put_autosuspend(struct gbphy_device *gbphy_dev) {}
++static inline void gbphy_runtime_get_noresume(struct gbphy_device *gbphy_dev) {}
++static inline void gbphy_runtime_put_noidle(struct gbphy_device *gbphy_dev) {}
++#endif
++
++#endif /* __GBPHY_H */
++
diff --git a/greybus_gpio.patch b/greybus_gpio.patch
new file mode 100644
index 00000000000000..743837044b239d
--- /dev/null
+++ b/greybus_gpio.patch
@@ -0,0 +1,774 @@
+---
+ drivers/greybus/gpio.c | 767 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 767 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/gpio.c
+@@ -0,0 +1,767 @@
++/*
++ * GPIO Greybus driver.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/mutex.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++struct gb_gpio_line {
++ /* The following has to be an array of line_max entries */
++ /* --> make them just a flags field */
++ u8 active: 1,
++ direction: 1, /* 0 = output, 1 = input */
++ value: 1; /* 0 = low, 1 = high */
++ u16 debounce_usec;
++
++ u8 irq_type;
++ bool irq_type_pending;
++ bool masked;
++ bool masked_pending;
++};
++
++struct gb_gpio_controller {
++ struct gbphy_device *gbphy_dev;
++ struct gb_connection *connection;
++ u8 line_max; /* max line number */
++ struct gb_gpio_line *lines;
++
++ struct gpio_chip chip;
++ struct irq_chip irqc;
++ struct irq_chip *irqchip;
++ struct irq_domain *irqdomain;
++ unsigned int irq_base;
++ irq_flow_handler_t irq_handler;
++ unsigned int irq_default_type;
++ struct mutex irq_lock;
++};
++#define gpio_chip_to_gb_gpio_controller(chip) \
++ container_of(chip, struct gb_gpio_controller, chip)
++#define irq_data_to_gpio_chip(d) (d->domain->host_data)
++
++static int gb_gpio_line_count_operation(struct gb_gpio_controller *ggc)
++{
++ struct gb_gpio_line_count_response response;
++ int ret;
++
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_LINE_COUNT,
++ NULL, 0, &response, sizeof(response));
++ if (!ret)
++ ggc->line_max = response.count;
++ return ret;
++}
++
++static int gb_gpio_activate_operation(struct gb_gpio_controller *ggc, u8 which)
++{
++ struct gb_gpio_activate_request request;
++ struct gbphy_device *gbphy_dev = ggc->gbphy_dev;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ request.which = which;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_ACTIVATE,
++ &request, sizeof(request), NULL, 0);
++ if (ret) {
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return ret;
++ }
++
++ ggc->lines[which].active = true;
++
++ return 0;
++}
++
++static void gb_gpio_deactivate_operation(struct gb_gpio_controller *ggc,
++ u8 which)
++{
++ struct gbphy_device *gbphy_dev = ggc->gbphy_dev;
++ struct device *dev = &gbphy_dev->dev;
++ struct gb_gpio_deactivate_request request;
++ int ret;
++
++ request.which = which;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DEACTIVATE,
++ &request, sizeof(request), NULL, 0);
++ if (ret) {
++ dev_err(dev, "failed to deactivate gpio %u\n", which);
++ goto out_pm_put;
++ }
++
++ ggc->lines[which].active = false;
++
++out_pm_put:
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++}
++
++static int gb_gpio_get_direction_operation(struct gb_gpio_controller *ggc,
++ u8 which)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_get_direction_request request;
++ struct gb_gpio_get_direction_response response;
++ int ret;
++ u8 direction;
++
++ request.which = which;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_DIRECTION,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret)
++ return ret;
++
++ direction = response.direction;
++ if (direction && direction != 1) {
++ dev_warn(dev, "gpio %u direction was %u (should be 0 or 1)\n",
++ which, direction);
++ }
++ ggc->lines[which].direction = direction ? 1 : 0;
++ return 0;
++}
++
++static int gb_gpio_direction_in_operation(struct gb_gpio_controller *ggc,
++ u8 which)
++{
++ struct gb_gpio_direction_in_request request;
++ int ret;
++
++ request.which = which;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_IN,
++ &request, sizeof(request), NULL, 0);
++ if (!ret)
++ ggc->lines[which].direction = 1;
++ return ret;
++}
++
++static int gb_gpio_direction_out_operation(struct gb_gpio_controller *ggc,
++ u8 which, bool value_high)
++{
++ struct gb_gpio_direction_out_request request;
++ int ret;
++
++ request.which = which;
++ request.value = value_high ? 1 : 0;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_OUT,
++ &request, sizeof(request), NULL, 0);
++ if (!ret)
++ ggc->lines[which].direction = 0;
++ return ret;
++}
++
++static int gb_gpio_get_value_operation(struct gb_gpio_controller *ggc,
++ u8 which)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_get_value_request request;
++ struct gb_gpio_get_value_response response;
++ int ret;
++ u8 value;
++
++ request.which = which;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_VALUE,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(dev, "failed to get value of gpio %u\n", which);
++ return ret;
++ }
++
++ value = response.value;
++ if (value && value != 1) {
++ dev_warn(dev, "gpio %u value was %u (should be 0 or 1)\n",
++ which, value);
++ }
++ ggc->lines[which].value = value ? 1 : 0;
++ return 0;
++}
++
++static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
++ u8 which, bool value_high)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_set_value_request request;
++ int ret;
++
++ if (ggc->lines[which].direction == 1) {
++ dev_warn(dev, "refusing to set value of input gpio %u\n",
++ which);
++ return;
++ }
++
++ request.which = which;
++ request.value = value_high ? 1 : 0;
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_VALUE,
++ &request, sizeof(request), NULL, 0);
++ if (ret) {
++ dev_err(dev, "failed to set value of gpio %u\n", which);
++ return;
++ }
++
++ ggc->lines[which].value = request.value;
++}
++
++static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *ggc,
++ u8 which, u16 debounce_usec)
++{
++ struct gb_gpio_set_debounce_request request;
++ int ret;
++
++ request.which = which;
++ request.usec = cpu_to_le16(debounce_usec);
++ ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_DEBOUNCE,
++ &request, sizeof(request), NULL, 0);
++ if (!ret)
++ ggc->lines[which].debounce_usec = debounce_usec;
++ return ret;
++}
++
++static void _gb_gpio_irq_mask(struct gb_gpio_controller *ggc, u8 hwirq)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_irq_mask_request request;
++ int ret;
++
++ request.which = hwirq;
++ ret = gb_operation_sync(ggc->connection,
++ GB_GPIO_TYPE_IRQ_MASK,
++ &request, sizeof(request), NULL, 0);
++ if (ret)
++ dev_err(dev, "failed to mask irq: %d\n", ret);
++}
++
++static void _gb_gpio_irq_unmask(struct gb_gpio_controller *ggc, u8 hwirq)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_irq_unmask_request request;
++ int ret;
++
++ request.which = hwirq;
++ ret = gb_operation_sync(ggc->connection,
++ GB_GPIO_TYPE_IRQ_UNMASK,
++ &request, sizeof(request), NULL, 0);
++ if (ret)
++ dev_err(dev, "failed to unmask irq: %d\n", ret);
++}
++
++static void _gb_gpio_irq_set_type(struct gb_gpio_controller *ggc,
++ u8 hwirq, u8 type)
++{
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_gpio_irq_type_request request;
++ int ret;
++
++ request.which = hwirq;
++ request.type = type;
++
++ ret = gb_operation_sync(ggc->connection,
++ GB_GPIO_TYPE_IRQ_TYPE,
++ &request, sizeof(request), NULL, 0);
++ if (ret)
++ dev_err(dev, "failed to set irq type: %d\n", ret);
++}
++
++static void gb_gpio_irq_mask(struct irq_data *d)
++{
++ struct gpio_chip *chip = irq_data_to_gpio_chip(d);
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ struct gb_gpio_line *line = &ggc->lines[d->hwirq];
++
++ line->masked = true;
++ line->masked_pending = true;
++}
++
++static void gb_gpio_irq_unmask(struct irq_data *d)
++{
++ struct gpio_chip *chip = irq_data_to_gpio_chip(d);
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ struct gb_gpio_line *line = &ggc->lines[d->hwirq];
++
++ line->masked = false;
++ line->masked_pending = true;
++}
++
++static int gb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
++{
++ struct gpio_chip *chip = irq_data_to_gpio_chip(d);
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ struct gb_gpio_line *line = &ggc->lines[d->hwirq];
++ struct device *dev = &ggc->gbphy_dev->dev;
++ u8 irq_type;
++
++ switch (type) {
++ case IRQ_TYPE_NONE:
++ irq_type = GB_GPIO_IRQ_TYPE_NONE;
++ break;
++ case IRQ_TYPE_EDGE_RISING:
++ irq_type = GB_GPIO_IRQ_TYPE_EDGE_RISING;
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ irq_type = GB_GPIO_IRQ_TYPE_EDGE_FALLING;
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ irq_type = GB_GPIO_IRQ_TYPE_EDGE_BOTH;
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ irq_type = GB_GPIO_IRQ_TYPE_LEVEL_LOW;
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ irq_type = GB_GPIO_IRQ_TYPE_LEVEL_HIGH;
++ break;
++ default:
++ dev_err(dev, "unsupported irq type: %u\n", type);
++ return -EINVAL;
++ }
++
++ line->irq_type = irq_type;
++ line->irq_type_pending = true;
++
++ return 0;
++}
++
++static void gb_gpio_irq_bus_lock(struct irq_data *d)
++{
++ struct gpio_chip *chip = irq_data_to_gpio_chip(d);
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ mutex_lock(&ggc->irq_lock);
++}
++
++static void gb_gpio_irq_bus_sync_unlock(struct irq_data *d)
++{
++ struct gpio_chip *chip = irq_data_to_gpio_chip(d);
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ struct gb_gpio_line *line = &ggc->lines[d->hwirq];
++
++ if (line->irq_type_pending) {
++ _gb_gpio_irq_set_type(ggc, d->hwirq, line->irq_type);
++ line->irq_type_pending = false;
++ }
++
++ if (line->masked_pending) {
++ if (line->masked)
++ _gb_gpio_irq_mask(ggc, d->hwirq);
++ else
++ _gb_gpio_irq_unmask(ggc, d->hwirq);
++ line->masked_pending = false;
++ }
++
++ mutex_unlock(&ggc->irq_lock);
++}
++
++static int gb_gpio_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_gpio_controller *ggc = gb_connection_get_data(connection);
++ struct device *dev = &ggc->gbphy_dev->dev;
++ struct gb_message *request;
++ struct gb_gpio_irq_event_request *event;
++ u8 type = op->type;
++ int irq;
++ struct irq_desc *desc;
++
++ if (type != GB_GPIO_TYPE_IRQ_EVENT) {
++ dev_err(dev, "unsupported unsolicited request: %u\n", type);
++ return -EINVAL;
++ }
++
++ request = op->request;
++
++ if (request->payload_size < sizeof(*event)) {
++ dev_err(dev, "short event received (%zu < %zu)\n",
++ request->payload_size, sizeof(*event));
++ return -EINVAL;
++ }
++
++ event = request->payload;
++ if (event->which > ggc->line_max) {
++ dev_err(dev, "invalid hw irq: %d\n", event->which);
++ return -EINVAL;
++ }
++
++ irq = irq_find_mapping(ggc->irqdomain, event->which);
++ if (!irq) {
++ dev_err(dev, "failed to find IRQ\n");
++ return -EINVAL;
++ }
++ desc = irq_to_desc(irq);
++ if (!desc) {
++ dev_err(dev, "failed to look up irq\n");
++ return -EINVAL;
++ }
++
++ local_irq_disable();
++ generic_handle_irq_desc(desc);
++ local_irq_enable();
++
++ return 0;
++}
++
++static int gb_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ return gb_gpio_activate_operation(ggc, (u8)offset);
++}
++
++static void gb_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ gb_gpio_deactivate_operation(ggc, (u8)offset);
++}
++
++static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ u8 which;
++ int ret;
++
++ which = (u8)offset;
++ ret = gb_gpio_get_direction_operation(ggc, which);
++ if (ret)
++ return ret;
++
++ return ggc->lines[which].direction ? 1 : 0;
++}
++
++static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ return gb_gpio_direction_in_operation(ggc, (u8)offset);
++}
++
++static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
++ int value)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ return gb_gpio_direction_out_operation(ggc, (u8)offset, !!value);
++}
++
++static int gb_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ u8 which;
++ int ret;
++
++ which = (u8)offset;
++ ret = gb_gpio_get_value_operation(ggc, which);
++ if (ret)
++ return ret;
++
++ return ggc->lines[which].value;
++}
++
++static void gb_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
++}
++
++static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
++ unsigned debounce)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++ u16 usec;
++
++ if (debounce > U16_MAX)
++ return -EINVAL;
++ usec = (u16)debounce;
++
++ return gb_gpio_set_debounce_operation(ggc, (u8)offset, usec);
++}
++
++static int gb_gpio_controller_setup(struct gb_gpio_controller *ggc)
++{
++ int ret;
++
++ /* Now find out how many lines there are */
++ ret = gb_gpio_line_count_operation(ggc);
++ if (ret)
++ return ret;
++
++ ggc->lines = kcalloc(ggc->line_max + 1, sizeof(*ggc->lines),
++ GFP_KERNEL);
++ if (!ggc->lines)
++ return -ENOMEM;
++
++ return ret;
++}
++
++/**
++ * gb_gpio_irq_map() - maps an IRQ into a GB gpio irqchip
++ * @d: the irqdomain used by this irqchip
++ * @irq: the global irq number used by this GB gpio irqchip irq
++ * @hwirq: the local IRQ/GPIO line offset on this GB gpio
++ *
++ * This function will set up the mapping for a certain IRQ line on a
++ * GB gpio by assigning the GB gpio as chip data, and using the irqchip
++ * stored inside the GB gpio.
++ */
++static int gb_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
++ irq_hw_number_t hwirq)
++{
++ struct gpio_chip *chip = domain->host_data;
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ irq_set_chip_data(irq, ggc);
++ irq_set_chip_and_handler(irq, ggc->irqchip, ggc->irq_handler);
++ irq_set_noprobe(irq);
++ /*
++ * No set-up of the hardware will happen if IRQ_TYPE_NONE
++ * is passed as default type.
++ */
++ if (ggc->irq_default_type != IRQ_TYPE_NONE)
++ irq_set_irq_type(irq, ggc->irq_default_type);
++
++ return 0;
++}
++
++static void gb_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
++{
++ irq_set_chip_and_handler(irq, NULL, NULL);
++ irq_set_chip_data(irq, NULL);
++}
++
++static const struct irq_domain_ops gb_gpio_domain_ops = {
++ .map = gb_gpio_irq_map,
++ .unmap = gb_gpio_irq_unmap,
++};
++
++/**
++ * gb_gpio_irqchip_remove() - removes an irqchip added to a gb_gpio_controller
++ * @ggc: the gb_gpio_controller to remove the irqchip from
++ *
++ * This is called only from gb_gpio_remove()
++ */
++static void gb_gpio_irqchip_remove(struct gb_gpio_controller *ggc)
++{
++ unsigned int offset;
++
++ /* Remove all IRQ mappings and delete the domain */
++ if (ggc->irqdomain) {
++ for (offset = 0; offset < (ggc->line_max + 1); offset++)
++ irq_dispose_mapping(irq_find_mapping(ggc->irqdomain, offset));
++ irq_domain_remove(ggc->irqdomain);
++ }
++
++ if (ggc->irqchip) {
++ ggc->irqchip = NULL;
++ }
++}
++
++/**
++ * gb_gpio_irqchip_add() - adds an irqchip to a gpio chip
++ * @chip: the gpio chip to add the irqchip to
++ * @irqchip: the irqchip to add to the adapter
++ * @first_irq: if not dynamically assigned, the base (first) IRQ to
++ * allocate gpio irqs from
++ * @handler: the irq handler to use (often a predefined irq core function)
++ * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
++ * to have the core avoid setting up any default type in the hardware.
++ *
++ * This function closely associates a certain irqchip with a certain
++ * gpio chip, providing an irq domain to translate the local IRQs to
++ * global irqs, and making sure that the gpio chip
++ * is passed as chip data to all related functions. Driver callbacks
++ * need to use container_of() to get their local state containers back
++ * from the gpio chip passed as chip data. An irqdomain will be stored
++ * in the gpio chip that shall be used by the driver to handle IRQ number
++ * translation. The gpio chip will need to be initialized and registered
++ * before calling this function.
++ */
++static int gb_gpio_irqchip_add(struct gpio_chip *chip,
++ struct irq_chip *irqchip,
++ unsigned int first_irq,
++ irq_flow_handler_t handler,
++ unsigned int type)
++{
++ struct gb_gpio_controller *ggc;
++ unsigned int offset;
++ unsigned irq_base;
++
++ if (!chip || !irqchip)
++ return -EINVAL;
++
++ ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ ggc->irqchip = irqchip;
++ ggc->irq_handler = handler;
++ ggc->irq_default_type = type;
++ ggc->irqdomain = irq_domain_add_simple(NULL,
++ ggc->line_max + 1, first_irq,
++ &gb_gpio_domain_ops, chip);
++ if (!ggc->irqdomain) {
++ ggc->irqchip = NULL;
++ return -EINVAL;
++ }
++
++ /*
++ * Prepare the mapping since the irqchip shall be orthogonal to
++ * any gpio calls. If the first_irq was zero, this is
++ * necessary to allocate descriptors for all IRQs.
++ */
++ for (offset = 0; offset < (ggc->line_max + 1); offset++) {
++ irq_base = irq_create_mapping(ggc->irqdomain, offset);
++ if (offset == 0)
++ ggc->irq_base = irq_base;
++ }
++
++ return 0;
++}
++
++static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
++
++ return irq_find_mapping(ggc->irqdomain, offset);
++}
++
++static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ struct gb_gpio_controller *ggc;
++ struct gpio_chip *gpio;
++ struct irq_chip *irqc;
++ int ret;
++
++ ggc = kzalloc(sizeof(*ggc), GFP_KERNEL);
++ if (!ggc)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ gb_gpio_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto exit_ggc_free;
++ }
++
++ ggc->connection = connection;
++ gb_connection_set_data(connection, ggc);
++ ggc->gbphy_dev = gbphy_dev;
++ gb_gbphy_set_data(gbphy_dev, ggc);
++
++ ret = gb_connection_enable_tx(connection);
++ if (ret)
++ goto exit_connection_destroy;
++
++ ret = gb_gpio_controller_setup(ggc);
++ if (ret)
++ goto exit_connection_disable;
++
++ irqc = &ggc->irqc;
++ irqc->irq_mask = gb_gpio_irq_mask;
++ irqc->irq_unmask = gb_gpio_irq_unmask;
++ irqc->irq_set_type = gb_gpio_irq_set_type;
++ irqc->irq_bus_lock = gb_gpio_irq_bus_lock;
++ irqc->irq_bus_sync_unlock = gb_gpio_irq_bus_sync_unlock;
++ irqc->name = "greybus_gpio";
++
++ mutex_init(&ggc->irq_lock);
++
++ gpio = &ggc->chip;
++
++ gpio->label = "greybus_gpio";
++ gpio->parent = &gbphy_dev->dev;
++ gpio->owner = THIS_MODULE;
++
++ gpio->request = gb_gpio_request;
++ gpio->free = gb_gpio_free;
++ gpio->get_direction = gb_gpio_get_direction;
++ gpio->direction_input = gb_gpio_direction_input;
++ gpio->direction_output = gb_gpio_direction_output;
++ gpio->get = gb_gpio_get;
++ gpio->set = gb_gpio_set;
++ gpio->set_debounce = gb_gpio_set_debounce;
++ gpio->to_irq = gb_gpio_to_irq;
++ gpio->base = -1; /* Allocate base dynamically */
++ gpio->ngpio = ggc->line_max + 1;
++ gpio->can_sleep = true;
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto exit_line_free;
++
++ ret = gpiochip_add(gpio);
++ if (ret) {
++ dev_err(&connection->bundle->dev,
++ "failed to add gpio chip: %d\n", ret);
++ goto exit_line_free;
++ }
++
++ ret = gb_gpio_irqchip_add(gpio, irqc, 0,
++ handle_level_irq, IRQ_TYPE_NONE);
++ if (ret) {
++ dev_err(&connection->bundle->dev,
++ "failed to add irq chip: %d\n", ret);
++ goto exit_gpiochip_remove;
++ }
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return 0;
++
++exit_gpiochip_remove:
++ gpiochip_remove(gpio);
++exit_line_free:
++ kfree(ggc->lines);
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_ggc_free:
++ kfree(ggc);
++ return ret;
++}
++
++static void gb_gpio_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_gpio_controller *ggc = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = ggc->connection;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ gb_connection_disable_rx(connection);
++ gb_gpio_irqchip_remove(ggc);
++ gpiochip_remove(&ggc->chip);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++ kfree(ggc->lines);
++ kfree(ggc);
++}
++
++static const struct gbphy_device_id gb_gpio_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_GPIO) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_gpio_id_table);
++
++static struct gbphy_driver gpio_driver = {
++ .name = "gpio",
++ .probe = gb_gpio_probe,
++ .remove = gb_gpio_remove,
++ .id_table = gb_gpio_id_table,
++};
++
++module_gbphy_driver(gpio_driver);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_hd.patch b/greybus_hd.patch
new file mode 100644
index 00000000000000..2f5d5629cc5878
--- /dev/null
+++ b/greybus_hd.patch
@@ -0,0 +1,358 @@
+---
+ drivers/greybus/hd.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/hd.h | 90 +++++++++++++++++
+ 2 files changed, 347 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/hd.c
+@@ -0,0 +1,257 @@
++/*
++ * Greybus Host Device
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_create);
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_release);
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_add);
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_del);
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_in);
++EXPORT_TRACEPOINT_SYMBOL_GPL(gb_message_submit);
++
++static struct ida gb_hd_bus_id_map;
++
++int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
++ bool async)
++{
++ if (!hd || !hd->driver || !hd->driver->output)
++ return -EINVAL;
++ return hd->driver->output(hd, req, size, cmd, async);
++}
++EXPORT_SYMBOL_GPL(gb_hd_output);
++
++static ssize_t bus_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_host_device *hd = to_gb_host_device(dev);
++
++ return sprintf(buf, "%d\n", hd->bus_id);
++}
++static DEVICE_ATTR_RO(bus_id);
++
++static struct attribute *bus_attrs[] = {
++ &dev_attr_bus_id.attr,
++ NULL
++};
++ATTRIBUTE_GROUPS(bus);
++
++int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id)
++{
++ struct ida *id_map = &hd->cport_id_map;
++ int ret;
++
++ ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL);
++ if (ret < 0) {
++ dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id);
++ return ret;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_hd_cport_reserve);
++
++void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id)
++{
++ struct ida *id_map = &hd->cport_id_map;
++
++ ida_simple_remove(id_map, cport_id);
++}
++EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved);
++
++/* Locking: Caller guarantees serialisation */
++int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
++ unsigned long flags)
++{
++ struct ida *id_map = &hd->cport_id_map;
++ int ida_start, ida_end;
++
++ if (hd->driver->cport_allocate)
++ return hd->driver->cport_allocate(hd, cport_id, flags);
++
++ if (cport_id < 0) {
++ ida_start = 0;
++ ida_end = hd->num_cports;
++ } else if (cport_id < hd->num_cports) {
++ ida_start = cport_id;
++ ida_end = cport_id + 1;
++ } else {
++ dev_err(&hd->dev, "cport %d not available\n", cport_id);
++ return -EINVAL;
++ }
++
++ return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
++}
++
++/* Locking: Caller guarantees serialisation */
++void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id)
++{
++ if (hd->driver->cport_release) {
++ hd->driver->cport_release(hd, cport_id);
++ return;
++ }
++
++ ida_simple_remove(&hd->cport_id_map, cport_id);
++}
++
++static void gb_hd_release(struct device *dev)
++{
++ struct gb_host_device *hd = to_gb_host_device(dev);
++
++ trace_gb_hd_release(hd);
++
++ if (hd->svc)
++ gb_svc_put(hd->svc);
++ ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
++ ida_destroy(&hd->cport_id_map);
++ kfree(hd);
++}
++
++struct device_type greybus_hd_type = {
++ .name = "greybus_host_device",
++ .release = gb_hd_release,
++};
++
++struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
++ struct device *parent,
++ size_t buffer_size_max,
++ size_t num_cports)
++{
++ struct gb_host_device *hd;
++ int ret;
++
++ /*
++ * Validate that the driver implements all of the callbacks
++ * so that we don't have to every time we make them.
++ */
++ if ((!driver->message_send) || (!driver->message_cancel)) {
++ dev_err(parent, "mandatory hd-callbacks missing\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
++ dev_err(parent, "greybus host-device buffers too small\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (num_cports == 0 || num_cports > CPORT_ID_MAX + 1) {
++ dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports);
++ return ERR_PTR(-EINVAL);
++ }
++
++ /*
++ * Make sure to never allocate messages larger than what the Greybus
++ * protocol supports.
++ */
++ if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
++ dev_warn(parent, "limiting buffer size to %u\n",
++ GB_OPERATION_MESSAGE_SIZE_MAX);
++ buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
++ }
++
++ hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
++ if (!hd)
++ return ERR_PTR(-ENOMEM);
++
++ ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
++ if (ret < 0) {
++ kfree(hd);
++ return ERR_PTR(ret);
++ }
++ hd->bus_id = ret;
++
++ hd->driver = driver;
++ INIT_LIST_HEAD(&hd->modules);
++ INIT_LIST_HEAD(&hd->connections);
++ ida_init(&hd->cport_id_map);
++ hd->buffer_size_max = buffer_size_max;
++ hd->num_cports = num_cports;
++
++ hd->dev.parent = parent;
++ hd->dev.bus = &greybus_bus_type;
++ hd->dev.type = &greybus_hd_type;
++ hd->dev.groups = bus_groups;
++ hd->dev.dma_mask = hd->dev.parent->dma_mask;
++ device_initialize(&hd->dev);
++ dev_set_name(&hd->dev, "greybus%d", hd->bus_id);
++
++ trace_gb_hd_create(hd);
++
++ hd->svc = gb_svc_create(hd);
++ if (!hd->svc) {
++ dev_err(&hd->dev, "failed to create svc\n");
++ put_device(&hd->dev);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ return hd;
++}
++EXPORT_SYMBOL_GPL(gb_hd_create);
++
++int gb_hd_add(struct gb_host_device *hd)
++{
++ int ret;
++
++ ret = device_add(&hd->dev);
++ if (ret)
++ return ret;
++
++ ret = gb_svc_add(hd->svc);
++ if (ret) {
++ device_del(&hd->dev);
++ return ret;
++ }
++
++ trace_gb_hd_add(hd);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_hd_add);
++
++void gb_hd_del(struct gb_host_device *hd)
++{
++ trace_gb_hd_del(hd);
++
++ /*
++ * Tear down the svc and flush any on-going hotplug processing before
++ * removing the remaining interfaces.
++ */
++ gb_svc_del(hd->svc);
++
++ device_del(&hd->dev);
++}
++EXPORT_SYMBOL_GPL(gb_hd_del);
++
++void gb_hd_shutdown(struct gb_host_device *hd)
++{
++ gb_svc_del(hd->svc);
++}
++EXPORT_SYMBOL_GPL(gb_hd_shutdown);
++
++void gb_hd_put(struct gb_host_device *hd)
++{
++ put_device(&hd->dev);
++}
++EXPORT_SYMBOL_GPL(gb_hd_put);
++
++int __init gb_hd_init(void)
++{
++ ida_init(&gb_hd_bus_id_map);
++
++ return 0;
++}
++
++void gb_hd_exit(void)
++{
++ ida_destroy(&gb_hd_bus_id_map);
++}
+--- /dev/null
++++ b/drivers/greybus/hd.h
+@@ -0,0 +1,90 @@
++/*
++ * Greybus Host Device
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __HD_H
++#define __HD_H
++
++struct gb_host_device;
++struct gb_message;
++
++struct gb_hd_driver {
++ size_t hd_priv_size;
++
++ int (*cport_allocate)(struct gb_host_device *hd, int cport_id,
++ unsigned long flags);
++ void (*cport_release)(struct gb_host_device *hd, u16 cport_id);
++ int (*cport_enable)(struct gb_host_device *hd, u16 cport_id,
++ unsigned long flags);
++ int (*cport_disable)(struct gb_host_device *hd, u16 cport_id);
++ int (*cport_connected)(struct gb_host_device *hd, u16 cport_id);
++ int (*cport_flush)(struct gb_host_device *hd, u16 cport_id);
++ int (*cport_shutdown)(struct gb_host_device *hd, u16 cport_id,
++ u8 phase, unsigned int timeout);
++ int (*cport_quiesce)(struct gb_host_device *hd, u16 cport_id,
++ size_t peer_space, unsigned int timeout);
++ int (*cport_clear)(struct gb_host_device *hd, u16 cport_id);
++
++ int (*message_send)(struct gb_host_device *hd, u16 dest_cport_id,
++ struct gb_message *message, gfp_t gfp_mask);
++ void (*message_cancel)(struct gb_message *message);
++ int (*latency_tag_enable)(struct gb_host_device *hd, u16 cport_id);
++ int (*latency_tag_disable)(struct gb_host_device *hd, u16 cport_id);
++ int (*output)(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
++ bool async);
++ int (*timesync_enable)(struct gb_host_device *hd, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk);
++ int (*timesync_disable)(struct gb_host_device *hd);
++ int (*timesync_authoritative)(struct gb_host_device *hd,
++ u64 *frame_time);
++ int (*timesync_get_last_event)(struct gb_host_device *hd,
++ u64 *frame_time);
++};
++
++struct gb_host_device {
++ struct device dev;
++ int bus_id;
++ const struct gb_hd_driver *driver;
++
++ struct list_head modules;
++ struct list_head connections;
++ struct ida cport_id_map;
++
++ /* Number of CPorts supported by the UniPro IP */
++ size_t num_cports;
++
++ /* Host device buffer constraints */
++ size_t buffer_size_max;
++
++ struct gb_svc *svc;
++ /* Private data for the host driver */
++ unsigned long hd_priv[0] __aligned(sizeof(s64));
++};
++#define to_gb_host_device(d) container_of(d, struct gb_host_device, dev)
++
++int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id);
++void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id);
++int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
++ unsigned long flags);
++void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id);
++
++struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
++ struct device *parent,
++ size_t buffer_size_max,
++ size_t num_cports);
++int gb_hd_add(struct gb_host_device *hd);
++void gb_hd_del(struct gb_host_device *hd);
++void gb_hd_shutdown(struct gb_host_device *hd);
++void gb_hd_put(struct gb_host_device *hd);
++int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
++ bool in_irq);
++
++int gb_hd_init(void);
++void gb_hd_exit(void);
++
++#endif /* __HD_H */
diff --git a/greybus_hid.patch b/greybus_hid.patch
new file mode 100644
index 00000000000000..c449705c314f0e
--- /dev/null
+++ b/greybus_hid.patch
@@ -0,0 +1,543 @@
+---
+ drivers/greybus/hid.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 536 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/hid.c
+@@ -0,0 +1,536 @@
++/*
++ * HID class driver for the Greybus.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/bitops.h>
++#include <linux/hid.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++
++#include "greybus.h"
++
++/* Greybus HID device's structure */
++struct gb_hid {
++ struct gb_bundle *bundle;
++ struct gb_connection *connection;
++
++ struct hid_device *hid;
++ struct gb_hid_desc_response hdesc;
++
++ unsigned long flags;
++#define GB_HID_STARTED 0x01
++#define GB_HID_READ_PENDING 0x04
++
++ unsigned int bufsize;
++ char *inbuf;
++};
++
++static DEFINE_MUTEX(gb_hid_open_mutex);
++
++/* Routines to get controller's information over greybus */
++
++/* Operations performed on greybus */
++static int gb_hid_get_desc(struct gb_hid *ghid)
++{
++ return gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_DESC, NULL,
++ 0, &ghid->hdesc, sizeof(ghid->hdesc));
++}
++
++static int gb_hid_get_report_desc(struct gb_hid *ghid, char *rdesc)
++{
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(ghid->bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_REPORT_DESC,
++ NULL, 0, rdesc,
++ le16_to_cpu(ghid->hdesc.wReportDescLength));
++
++ gb_pm_runtime_put_autosuspend(ghid->bundle);
++
++ return ret;
++}
++
++static int gb_hid_set_power(struct gb_hid *ghid, int type)
++{
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(ghid->bundle);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(ghid->connection, type, NULL, 0, NULL, 0);
++
++ gb_pm_runtime_put_autosuspend(ghid->bundle);
++
++ return ret;
++}
++
++static int gb_hid_get_report(struct gb_hid *ghid, u8 report_type, u8 report_id,
++ unsigned char *buf, int len)
++{
++ struct gb_hid_get_report_request request;
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(ghid->bundle);
++ if (ret)
++ return ret;
++
++ request.report_type = report_type;
++ request.report_id = report_id;
++
++ ret = gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_REPORT,
++ &request, sizeof(request), buf, len);
++
++ gb_pm_runtime_put_autosuspend(ghid->bundle);
++
++ return ret;
++}
++
++static int gb_hid_set_report(struct gb_hid *ghid, u8 report_type, u8 report_id,
++ unsigned char *buf, int len)
++{
++ struct gb_hid_set_report_request *request;
++ struct gb_operation *operation;
++ int ret, size = sizeof(*request) + len - 1;
++
++ ret = gb_pm_runtime_get_sync(ghid->bundle);
++ if (ret)
++ return ret;
++
++ operation = gb_operation_create(ghid->connection,
++ GB_HID_TYPE_SET_REPORT, size, 0,
++ GFP_KERNEL);
++ if (!operation) {
++ gb_pm_runtime_put_autosuspend(ghid->bundle);
++ return -ENOMEM;
++ }
++
++ request = operation->request->payload;
++ request->report_type = report_type;
++ request->report_id = report_id;
++ memcpy(request->report, buf, len);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret) {
++ dev_err(&operation->connection->bundle->dev,
++ "failed to set report: %d\n", ret);
++ } else {
++ ret = len;
++ }
++
++ gb_operation_put(operation);
++ gb_pm_runtime_put_autosuspend(ghid->bundle);
++
++ return ret;
++}
++
++static int gb_hid_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_hid *ghid = gb_connection_get_data(connection);
++ struct gb_hid_input_report_request *request = op->request->payload;
++
++ if (op->type != GB_HID_TYPE_IRQ_EVENT) {
++ dev_err(&connection->bundle->dev,
++ "unsupported unsolicited request\n");
++ return -EINVAL;
++ }
++
++ if (test_bit(GB_HID_STARTED, &ghid->flags))
++ hid_input_report(ghid->hid, HID_INPUT_REPORT,
++ request->report, op->request->payload_size, 1);
++
++ return 0;
++}
++
++static int gb_hid_report_len(struct hid_report *report)
++{
++ return ((report->size - 1) >> 3) + 1 +
++ report->device->report_enum[report->type].numbered;
++}
++
++static void gb_hid_find_max_report(struct hid_device *hid, unsigned int type,
++ unsigned int *max)
++{
++ struct hid_report *report;
++ unsigned int size;
++
++ list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
++ size = gb_hid_report_len(report);
++ if (*max < size)
++ *max = size;
++ }
++}
++
++static void gb_hid_free_buffers(struct gb_hid *ghid)
++{
++ kfree(ghid->inbuf);
++ ghid->inbuf = NULL;
++ ghid->bufsize = 0;
++}
++
++static int gb_hid_alloc_buffers(struct gb_hid *ghid, size_t bufsize)
++{
++ ghid->inbuf = kzalloc(bufsize, GFP_KERNEL);
++ if (!ghid->inbuf)
++ return -ENOMEM;
++
++ ghid->bufsize = bufsize;
++
++ return 0;
++}
++
++/* Routines dealing with reports */
++static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report)
++{
++ unsigned int size;
++
++ size = gb_hid_report_len(report);
++ if (gb_hid_get_report(ghid, report->type, report->id, ghid->inbuf,
++ size))
++ return;
++
++ /*
++ * hid->driver_lock is held as we are in probe function,
++ * we just need to setup the input fields, so using
++ * hid_report_raw_event is safe.
++ */
++ hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, size, 1);
++}
++
++static void gb_hid_init_reports(struct gb_hid *ghid)
++{
++ struct hid_device *hid = ghid->hid;
++ struct hid_report *report;
++
++ list_for_each_entry(report,
++ &hid->report_enum[HID_INPUT_REPORT].report_list, list)
++ gb_hid_init_report(ghid, report);
++
++ list_for_each_entry(report,
++ &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
++ gb_hid_init_report(ghid, report);
++}
++
++static int __gb_hid_get_raw_report(struct hid_device *hid,
++ unsigned char report_number, __u8 *buf, size_t count,
++ unsigned char report_type)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ int ret;
++
++ if (report_type == HID_OUTPUT_REPORT)
++ return -EINVAL;
++
++ ret = gb_hid_get_report(ghid, report_type, report_number, buf, count);
++ if (!ret)
++ ret = count;
++
++ return ret;
++}
++
++static int __gb_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
++ size_t len, unsigned char report_type)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ int report_id = buf[0];
++ int ret;
++
++ if (report_type == HID_INPUT_REPORT)
++ return -EINVAL;
++
++ if (report_id) {
++ buf++;
++ len--;
++ }
++
++ ret = gb_hid_set_report(ghid, report_type, report_id, buf, len);
++ if (report_id && ret >= 0)
++ ret++; /* add report_id to the number of transfered bytes */
++
++ return 0;
++}
++
++static int gb_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
++ __u8 *buf, size_t len, unsigned char rtype,
++ int reqtype)
++{
++ switch (reqtype) {
++ case HID_REQ_GET_REPORT:
++ return __gb_hid_get_raw_report(hid, reportnum, buf, len, rtype);
++ case HID_REQ_SET_REPORT:
++ if (buf[0] != reportnum)
++ return -EINVAL;
++ return __gb_hid_output_raw_report(hid, buf, len, rtype);
++ default:
++ return -EIO;
++ }
++}
++
++/* HID Callbacks */
++static int gb_hid_parse(struct hid_device *hid)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ unsigned int rsize;
++ char *rdesc;
++ int ret;
++
++ rsize = le16_to_cpu(ghid->hdesc.wReportDescLength);
++ if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
++ dbg_hid("weird size of report descriptor (%u)\n", rsize);
++ return -EINVAL;
++ }
++
++ rdesc = kzalloc(rsize, GFP_KERNEL);
++ if (!rdesc) {
++ dbg_hid("couldn't allocate rdesc memory\n");
++ return -ENOMEM;
++ }
++
++ ret = gb_hid_get_report_desc(ghid, rdesc);
++ if (ret) {
++ hid_err(hid, "reading report descriptor failed\n");
++ goto free_rdesc;
++ }
++
++ ret = hid_parse_report(hid, rdesc, rsize);
++ if (ret)
++ dbg_hid("parsing report descriptor failed\n");
++
++free_rdesc:
++ kfree(rdesc);
++
++ return ret;
++}
++
++static int gb_hid_start(struct hid_device *hid)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ unsigned int bufsize = HID_MIN_BUFFER_SIZE;
++ int ret;
++
++ gb_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize);
++ gb_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize);
++ gb_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize);
++
++ if (bufsize > HID_MAX_BUFFER_SIZE)
++ bufsize = HID_MAX_BUFFER_SIZE;
++
++ ret = gb_hid_alloc_buffers(ghid, bufsize);
++ if (ret)
++ return ret;
++
++ if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
++ gb_hid_init_reports(ghid);
++
++ return 0;
++}
++
++static void gb_hid_stop(struct hid_device *hid)
++{
++ struct gb_hid *ghid = hid->driver_data;
++
++ gb_hid_free_buffers(ghid);
++}
++
++static int gb_hid_open(struct hid_device *hid)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ int ret = 0;
++
++ mutex_lock(&gb_hid_open_mutex);
++ if (!hid->open++) {
++ ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON);
++ if (ret < 0)
++ hid->open--;
++ else
++ set_bit(GB_HID_STARTED, &ghid->flags);
++ }
++ mutex_unlock(&gb_hid_open_mutex);
++
++ return ret;
++}
++
++static void gb_hid_close(struct hid_device *hid)
++{
++ struct gb_hid *ghid = hid->driver_data;
++ int ret;
++
++ /*
++ * Protecting hid->open to make sure we don't restart data acquistion
++ * due to a resumption we no longer care about..
++ */
++ mutex_lock(&gb_hid_open_mutex);
++ if (!--hid->open) {
++ clear_bit(GB_HID_STARTED, &ghid->flags);
++
++ /* Save some power */
++ ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF);
++ if (ret)
++ dev_err(&ghid->connection->bundle->dev,
++ "failed to power off (%d)\n", ret);
++ }
++ mutex_unlock(&gb_hid_open_mutex);
++}
++
++static int gb_hid_power(struct hid_device *hid, int lvl)
++{
++ struct gb_hid *ghid = hid->driver_data;
++
++ switch (lvl) {
++ case PM_HINT_FULLON:
++ return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON);
++ case PM_HINT_NORMAL:
++ return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF);
++ }
++
++ return 0;
++}
++
++/* HID structure to pass callbacks */
++static struct hid_ll_driver gb_hid_ll_driver = {
++ .parse = gb_hid_parse,
++ .start = gb_hid_start,
++ .stop = gb_hid_stop,
++ .open = gb_hid_open,
++ .close = gb_hid_close,
++ .power = gb_hid_power,
++ .raw_request = gb_hid_raw_request,
++};
++
++static int gb_hid_init(struct gb_hid *ghid)
++{
++ struct hid_device *hid = ghid->hid;
++ int ret;
++
++ ret = gb_hid_get_desc(ghid);
++ if (ret)
++ return ret;
++
++ hid->version = le16_to_cpu(ghid->hdesc.bcdHID);
++ hid->vendor = le16_to_cpu(ghid->hdesc.wVendorID);
++ hid->product = le16_to_cpu(ghid->hdesc.wProductID);
++ hid->country = ghid->hdesc.bCountryCode;
++
++ hid->driver_data = ghid;
++ hid->ll_driver = &gb_hid_ll_driver;
++ hid->dev.parent = &ghid->connection->bundle->dev;
++// hid->bus = BUS_GREYBUS; /* Need a bustype for GREYBUS in <linux/input.h> */
++
++ /* Set HID device's name */
++ snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",
++ dev_name(&ghid->connection->bundle->dev),
++ hid->vendor, hid->product);
++
++ return 0;
++}
++
++static int gb_hid_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct hid_device *hid;
++ struct gb_hid *ghid;
++ int ret;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_HID)
++ return -ENODEV;
++
++ ghid = kzalloc(sizeof(*ghid), GFP_KERNEL);
++ if (!ghid)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_hid_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto err_free_ghid;
++ }
++
++ gb_connection_set_data(connection, ghid);
++ ghid->connection = connection;
++
++ hid = hid_allocate_device();
++ if (IS_ERR(hid)) {
++ ret = PTR_ERR(hid);
++ goto err_connection_destroy;
++ }
++
++ ghid->hid = hid;
++ ghid->bundle = bundle;
++
++ greybus_set_drvdata(bundle, ghid);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto err_destroy_hid;
++
++ ret = gb_hid_init(ghid);
++ if (ret)
++ goto err_connection_disable;
++
++ ret = hid_add_device(hid);
++ if (ret) {
++ hid_err(hid, "can't add hid device: %d\n", ret);
++ goto err_connection_disable;
++ }
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++err_connection_disable:
++ gb_connection_disable(connection);
++err_destroy_hid:
++ hid_destroy_device(hid);
++err_connection_destroy:
++ gb_connection_destroy(connection);
++err_free_ghid:
++ kfree(ghid);
++
++ return ret;
++}
++
++static void gb_hid_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_hid *ghid = greybus_get_drvdata(bundle);
++
++ if (gb_pm_runtime_get_sync(bundle))
++ gb_pm_runtime_get_noresume(bundle);
++
++ hid_destroy_device(ghid->hid);
++ gb_connection_disable(ghid->connection);
++ gb_connection_destroy(ghid->connection);
++ kfree(ghid);
++}
++
++static const struct greybus_bundle_id gb_hid_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_hid_id_table);
++
++static struct greybus_driver gb_hid_driver = {
++ .name = "hid",
++ .probe = gb_hid_probe,
++ .disconnect = gb_hid_disconnect,
++ .id_table = gb_hid_id_table,
++};
++module_greybus_driver(gb_hid_driver);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_i2c.patch b/greybus_i2c.patch
new file mode 100644
index 00000000000000..e739a058e339b5
--- /dev/null
+++ b/greybus_i2c.patch
@@ -0,0 +1,350 @@
+---
+ drivers/greybus/i2c.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 343 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/i2c.c
+@@ -0,0 +1,343 @@
++/*
++ * I2C bridge driver for the Greybus "generic" I2C module.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++struct gb_i2c_device {
++ struct gb_connection *connection;
++ struct gbphy_device *gbphy_dev;
++
++ u32 functionality;
++
++ struct i2c_adapter adapter;
++};
++
++/*
++ * Map Greybus i2c functionality bits into Linux ones
++ */
++static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)
++{
++ return gb_i2c_functionality; /* All bits the same for now */
++}
++
++static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
++{
++ struct gb_i2c_functionality_response response;
++ u32 functionality;
++ int ret;
++
++ ret = gb_operation_sync(gb_i2c_dev->connection,
++ GB_I2C_TYPE_FUNCTIONALITY,
++ NULL, 0, &response, sizeof(response));
++ if (ret)
++ return ret;
++
++ functionality = le32_to_cpu(response.functionality);
++ gb_i2c_dev->functionality = gb_i2c_functionality_map(functionality);
++
++ return 0;
++}
++
++/*
++ * Map Linux i2c_msg flags into Greybus i2c transfer op flags.
++ */
++static u16 gb_i2c_transfer_op_flags_map(u16 flags)
++{
++ return flags; /* All flags the same for now */
++}
++
++static void
++gb_i2c_fill_transfer_op(struct gb_i2c_transfer_op *op, struct i2c_msg *msg)
++{
++ u16 flags = gb_i2c_transfer_op_flags_map(msg->flags);
++
++ op->addr = cpu_to_le16(msg->addr);
++ op->flags = cpu_to_le16(flags);
++ op->size = cpu_to_le16(msg->len);
++}
++
++static struct gb_operation *
++gb_i2c_operation_create(struct gb_connection *connection,
++ struct i2c_msg *msgs, u32 msg_count)
++{
++ struct gb_i2c_device *gb_i2c_dev = gb_connection_get_data(connection);
++ struct gb_i2c_transfer_request *request;
++ struct gb_operation *operation;
++ struct gb_i2c_transfer_op *op;
++ struct i2c_msg *msg;
++ u32 data_out_size = 0;
++ u32 data_in_size = 0;
++ size_t request_size;
++ void *data;
++ u16 op_count;
++ u32 i;
++
++ if (msg_count > (u32)U16_MAX) {
++ dev_err(&gb_i2c_dev->gbphy_dev->dev, "msg_count (%u) too big\n",
++ msg_count);
++ return NULL;
++ }
++ op_count = (u16)msg_count;
++
++ /*
++ * In addition to space for all message descriptors we need
++ * to have enough to hold all outbound message data.
++ */
++ msg = msgs;
++ for (i = 0; i < msg_count; i++, msg++)
++ if (msg->flags & I2C_M_RD)
++ data_in_size += (u32)msg->len;
++ else
++ data_out_size += (u32)msg->len;
++
++ request_size = sizeof(*request);
++ request_size += msg_count * sizeof(*op);
++ request_size += data_out_size;
++
++ /* Response consists only of incoming data */
++ operation = gb_operation_create(connection, GB_I2C_TYPE_TRANSFER,
++ request_size, data_in_size, GFP_KERNEL);
++ if (!operation)
++ return NULL;
++
++ request = operation->request->payload;
++ request->op_count = cpu_to_le16(op_count);
++ /* Fill in the ops array */
++ op = &request->ops[0];
++ msg = msgs;
++ for (i = 0; i < msg_count; i++)
++ gb_i2c_fill_transfer_op(op++, msg++);
++
++ if (!data_out_size)
++ return operation;
++
++ /* Copy over the outgoing data; it starts after the last op */
++ data = op;
++ msg = msgs;
++ for (i = 0; i < msg_count; i++) {
++ if (!(msg->flags & I2C_M_RD)) {
++ memcpy(data, msg->buf, msg->len);
++ data += msg->len;
++ }
++ msg++;
++ }
++
++ return operation;
++}
++
++static void gb_i2c_decode_response(struct i2c_msg *msgs, u32 msg_count,
++ struct gb_i2c_transfer_response *response)
++{
++ struct i2c_msg *msg = msgs;
++ u8 *data;
++ u32 i;
++
++ if (!response)
++ return;
++ data = response->data;
++ for (i = 0; i < msg_count; i++) {
++ if (msg->flags & I2C_M_RD) {
++ memcpy(msg->buf, data, msg->len);
++ data += msg->len;
++ }
++ msg++;
++ }
++}
++
++/*
++ * Some i2c transfer operations return results that are expected.
++ */
++static bool gb_i2c_expected_transfer_error(int errno)
++{
++ return errno == -EAGAIN || errno == -ENODEV;
++}
++
++static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,
++ struct i2c_msg *msgs, u32 msg_count)
++{
++ struct gb_connection *connection = gb_i2c_dev->connection;
++ struct device *dev = &gb_i2c_dev->gbphy_dev->dev;
++ struct gb_operation *operation;
++ int ret;
++
++ operation = gb_i2c_operation_create(connection, msgs, msg_count);
++ if (!operation)
++ return -ENOMEM;
++
++ ret = gbphy_runtime_get_sync(gb_i2c_dev->gbphy_dev);
++ if (ret)
++ goto exit_operation_put;
++
++ ret = gb_operation_request_send_sync(operation);
++ if (!ret) {
++ struct gb_i2c_transfer_response *response;
++
++ response = operation->response->payload;
++ gb_i2c_decode_response(msgs, msg_count, response);
++ ret = msg_count;
++ } else if (!gb_i2c_expected_transfer_error(ret)) {
++ dev_err(dev, "transfer operation failed (%d)\n", ret);
++ }
++
++ gbphy_runtime_put_autosuspend(gb_i2c_dev->gbphy_dev);
++
++exit_operation_put:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++ int msg_count)
++{
++ struct gb_i2c_device *gb_i2c_dev;
++
++ gb_i2c_dev = i2c_get_adapdata(adap);
++
++ return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);
++}
++
++#if 0
++/* Later */
++static int gb_i2c_smbus_xfer(struct i2c_adapter *adap,
++ u16 addr, unsigned short flags, char read_write,
++ u8 command, int size, union i2c_smbus_data *data)
++{
++ struct gb_i2c_device *gb_i2c_dev;
++
++ gb_i2c_dev = i2c_get_adapdata(adap);
++
++ return 0;
++}
++#endif
++
++static u32 gb_i2c_functionality(struct i2c_adapter *adap)
++{
++ struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);
++
++ return gb_i2c_dev->functionality;
++}
++
++static const struct i2c_algorithm gb_i2c_algorithm = {
++ .master_xfer = gb_i2c_master_xfer,
++ /* .smbus_xfer = gb_i2c_smbus_xfer, */
++ .functionality = gb_i2c_functionality,
++};
++
++/*
++ * Do initial setup of the i2c device. This includes verifying we
++ * can support it (based on the protocol version it advertises).
++ * If that's OK, we get and cached its functionality bits.
++ *
++ * Note: gb_i2c_dev->connection is assumed to have been valid.
++ */
++static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
++{
++ /* Assume the functionality never changes, just get it once */
++ return gb_i2c_functionality_operation(gb_i2c_dev);
++}
++
++static int gb_i2c_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ struct gb_i2c_device *gb_i2c_dev;
++ struct i2c_adapter *adapter;
++ int ret;
++
++ gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL);
++ if (!gb_i2c_dev)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ NULL);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto exit_i2cdev_free;
++ }
++
++ gb_i2c_dev->connection = connection;
++ gb_connection_set_data(connection, gb_i2c_dev);
++ gb_i2c_dev->gbphy_dev = gbphy_dev;
++ gb_gbphy_set_data(gbphy_dev, gb_i2c_dev);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto exit_connection_destroy;
++
++ ret = gb_i2c_device_setup(gb_i2c_dev);
++ if (ret)
++ goto exit_connection_disable;
++
++ /* Looks good; up our i2c adapter */
++ adapter = &gb_i2c_dev->adapter;
++ adapter->owner = THIS_MODULE;
++ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
++ adapter->algo = &gb_i2c_algorithm;
++ /* adapter->algo_data = what? */
++
++ adapter->dev.parent = &gbphy_dev->dev;
++ snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");
++ i2c_set_adapdata(adapter, gb_i2c_dev);
++
++ ret = i2c_add_adapter(adapter);
++ if (ret)
++ goto exit_connection_disable;
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return 0;
++
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_i2cdev_free:
++ kfree(gb_i2c_dev);
++
++ return ret;
++}
++
++static void gb_i2c_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_i2c_device *gb_i2c_dev = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = gb_i2c_dev->connection;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ i2c_del_adapter(&gb_i2c_dev->adapter);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++ kfree(gb_i2c_dev);
++}
++
++static const struct gbphy_device_id gb_i2c_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_I2C) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_i2c_id_table);
++
++static struct gbphy_driver i2c_driver = {
++ .name = "i2c",
++ .probe = gb_i2c_probe,
++ .remove = gb_i2c_remove,
++ .id_table = gb_i2c_id_table,
++};
++
++module_gbphy_driver(i2c_driver);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_interface.patch b/greybus_interface.patch
new file mode 100644
index 00000000000000..4285ce9f26969f
--- /dev/null
+++ b/greybus_interface.patch
@@ -0,0 +1,1415 @@
+---
+ drivers/greybus/interface.c | 1316 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/interface.h | 88 ++
+ 2 files changed, 1404 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/interface.c
+@@ -0,0 +1,1316 @@
++/*
++ * Greybus interface code
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/delay.h>
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++#define GB_INTERFACE_MODE_SWITCH_TIMEOUT 2000
++
++#define GB_INTERFACE_DEVICE_ID_BAD 0xff
++
++#define GB_INTERFACE_AUTOSUSPEND_MS 3000
++
++/* Time required for interface to enter standby before disabling REFCLK */
++#define GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS 20
++
++/* Don't-care selector index */
++#define DME_SELECTOR_INDEX_NULL 0
++
++/* DME attributes */
++/* FIXME: remove ES2 support and DME_T_TST_SRC_INCREMENT */
++#define DME_T_TST_SRC_INCREMENT 0x4083
++
++#define DME_DDBL1_MANUFACTURERID 0x5003
++#define DME_DDBL1_PRODUCTID 0x5004
++
++#define DME_TOSHIBA_GMP_VID 0x6000
++#define DME_TOSHIBA_GMP_PID 0x6001
++#define DME_TOSHIBA_GMP_SN0 0x6002
++#define DME_TOSHIBA_GMP_SN1 0x6003
++#define DME_TOSHIBA_GMP_INIT_STATUS 0x6101
++
++/* DDBL1 Manufacturer and Product ids */
++#define TOSHIBA_DMID 0x0126
++#define TOSHIBA_ES2_BRIDGE_DPID 0x1000
++#define TOSHIBA_ES3_APBRIDGE_DPID 0x1001
++#define TOSHIBA_ES3_GBPHY_DPID 0x1002
++
++static int gb_interface_hibernate_link(struct gb_interface *intf);
++static int gb_interface_refclk_set(struct gb_interface *intf, bool enable);
++
++static int gb_interface_dme_attr_get(struct gb_interface *intf,
++ u16 attr, u32 *val)
++{
++ return gb_svc_dme_peer_get(intf->hd->svc, intf->interface_id,
++ attr, DME_SELECTOR_INDEX_NULL, val);
++}
++
++static int gb_interface_read_ara_dme(struct gb_interface *intf)
++{
++ u32 sn0, sn1;
++ int ret;
++
++ /*
++ * Unless this is a Toshiba bridge, bail out until we have defined
++ * standard GMP attributes.
++ */
++ if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) {
++ dev_err(&intf->dev, "unknown manufacturer %08x\n",
++ intf->ddbl1_manufacturer_id);
++ return -ENODEV;
++ }
++
++ ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_VID,
++ &intf->vendor_id);
++ if (ret)
++ return ret;
++
++ ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_PID,
++ &intf->product_id);
++ if (ret)
++ return ret;
++
++ ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN0, &sn0);
++ if (ret)
++ return ret;
++
++ ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN1, &sn1);
++ if (ret)
++ return ret;
++
++ intf->serial_number = (u64)sn1 << 32 | sn0;
++
++ return 0;
++}
++
++static int gb_interface_read_dme(struct gb_interface *intf)
++{
++ int ret;
++
++ /* DME attributes have already been read */
++ if (intf->dme_read)
++ return 0;
++
++ ret = gb_interface_dme_attr_get(intf, DME_DDBL1_MANUFACTURERID,
++ &intf->ddbl1_manufacturer_id);
++ if (ret)
++ return ret;
++
++ ret = gb_interface_dme_attr_get(intf, DME_DDBL1_PRODUCTID,
++ &intf->ddbl1_product_id);
++ if (ret)
++ return ret;
++
++ if (intf->ddbl1_manufacturer_id == TOSHIBA_DMID &&
++ intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) {
++ intf->quirks |= GB_INTERFACE_QUIRK_NO_GMP_IDS;
++ intf->quirks |= GB_INTERFACE_QUIRK_NO_INIT_STATUS;
++ }
++
++ ret = gb_interface_read_ara_dme(intf);
++ if (ret)
++ return ret;
++
++ intf->dme_read = true;
++
++ return 0;
++}
++
++static int gb_interface_route_create(struct gb_interface *intf)
++{
++ struct gb_svc *svc = intf->hd->svc;
++ u8 intf_id = intf->interface_id;
++ u8 device_id;
++ int ret;
++
++ /* Allocate an interface device id. */
++ ret = ida_simple_get(&svc->device_id_map,
++ GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1,
++ GFP_KERNEL);
++ if (ret < 0) {
++ dev_err(&intf->dev, "failed to allocate device id: %d\n", ret);
++ return ret;
++ }
++ device_id = ret;
++
++ ret = gb_svc_intf_device_id(svc, intf_id, device_id);
++ if (ret) {
++ dev_err(&intf->dev, "failed to set device id %u: %d\n",
++ device_id, ret);
++ goto err_ida_remove;
++ }
++
++ /* FIXME: Hard-coded AP device id. */
++ ret = gb_svc_route_create(svc, svc->ap_intf_id, GB_SVC_DEVICE_ID_AP,
++ intf_id, device_id);
++ if (ret) {
++ dev_err(&intf->dev, "failed to create route: %d\n", ret);
++ goto err_svc_id_free;
++ }
++
++ intf->device_id = device_id;
++
++ return 0;
++
++err_svc_id_free:
++ /*
++ * XXX Should we tell SVC that this id doesn't belong to interface
++ * XXX anymore.
++ */
++err_ida_remove:
++ ida_simple_remove(&svc->device_id_map, device_id);
++
++ return ret;
++}
++
++static void gb_interface_route_destroy(struct gb_interface *intf)
++{
++ struct gb_svc *svc = intf->hd->svc;
++
++ if (intf->device_id == GB_INTERFACE_DEVICE_ID_BAD)
++ return;
++
++ gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id);
++ ida_simple_remove(&svc->device_id_map, intf->device_id);
++ intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
++}
++
++/* Locking: Caller holds the interface mutex. */
++static int gb_interface_legacy_mode_switch(struct gb_interface *intf)
++{
++ int ret;
++
++ dev_info(&intf->dev, "legacy mode switch detected\n");
++
++ /* Mark as disconnected to prevent I/O during disable. */
++ intf->disconnected = true;
++ gb_interface_disable(intf);
++ intf->disconnected = false;
++
++ ret = gb_interface_enable(intf);
++ if (ret) {
++ dev_err(&intf->dev, "failed to re-enable interface: %d\n", ret);
++ gb_interface_deactivate(intf);
++ }
++
++ return ret;
++}
++
++void gb_interface_mailbox_event(struct gb_interface *intf, u16 result,
++ u32 mailbox)
++{
++ mutex_lock(&intf->mutex);
++
++ if (result) {
++ dev_warn(&intf->dev,
++ "mailbox event with UniPro error: 0x%04x\n",
++ result);
++ goto err_disable;
++ }
++
++ if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) {
++ dev_warn(&intf->dev,
++ "mailbox event with unexpected value: 0x%08x\n",
++ mailbox);
++ goto err_disable;
++ }
++
++ if (intf->quirks & GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH) {
++ gb_interface_legacy_mode_switch(intf);
++ goto out_unlock;
++ }
++
++ if (!intf->mode_switch) {
++ dev_warn(&intf->dev, "unexpected mailbox event: 0x%08x\n",
++ mailbox);
++ goto err_disable;
++ }
++
++ dev_info(&intf->dev, "mode switch detected\n");
++
++ complete(&intf->mode_switch_completion);
++
++out_unlock:
++ mutex_unlock(&intf->mutex);
++
++ return;
++
++err_disable:
++ gb_interface_disable(intf);
++ gb_interface_deactivate(intf);
++ mutex_unlock(&intf->mutex);
++}
++
++static void gb_interface_mode_switch_work(struct work_struct *work)
++{
++ struct gb_interface *intf;
++ struct gb_control *control;
++ unsigned long timeout;
++ int ret;
++
++ intf = container_of(work, struct gb_interface, mode_switch_work);
++
++ mutex_lock(&intf->mutex);
++ /* Make sure interface is still enabled. */
++ if (!intf->enabled) {
++ dev_dbg(&intf->dev, "mode switch aborted\n");
++ intf->mode_switch = false;
++ mutex_unlock(&intf->mutex);
++ goto out_interface_put;
++ }
++
++ /*
++ * Prepare the control device for mode switch and make sure to get an
++ * extra reference before it goes away during interface disable.
++ */
++ control = gb_control_get(intf->control);
++ gb_control_mode_switch_prepare(control);
++ gb_interface_disable(intf);
++ mutex_unlock(&intf->mutex);
++
++ timeout = msecs_to_jiffies(GB_INTERFACE_MODE_SWITCH_TIMEOUT);
++ ret = wait_for_completion_interruptible_timeout(
++ &intf->mode_switch_completion, timeout);
++
++ /* Finalise control-connection mode switch. */
++ gb_control_mode_switch_complete(control);
++ gb_control_put(control);
++
++ if (ret < 0) {
++ dev_err(&intf->dev, "mode switch interrupted\n");
++ goto err_deactivate;
++ } else if (ret == 0) {
++ dev_err(&intf->dev, "mode switch timed out\n");
++ goto err_deactivate;
++ }
++
++ /* Re-enable (re-enumerate) interface if still active. */
++ mutex_lock(&intf->mutex);
++ intf->mode_switch = false;
++ if (intf->active) {
++ ret = gb_interface_enable(intf);
++ if (ret) {
++ dev_err(&intf->dev, "failed to re-enable interface: %d\n",
++ ret);
++ gb_interface_deactivate(intf);
++ }
++ }
++ mutex_unlock(&intf->mutex);
++
++out_interface_put:
++ gb_interface_put(intf);
++
++ return;
++
++err_deactivate:
++ mutex_lock(&intf->mutex);
++ intf->mode_switch = false;
++ gb_interface_deactivate(intf);
++ mutex_unlock(&intf->mutex);
++
++ gb_interface_put(intf);
++}
++
++int gb_interface_request_mode_switch(struct gb_interface *intf)
++{
++ int ret = 0;
++
++ mutex_lock(&intf->mutex);
++ if (intf->mode_switch) {
++ ret = -EBUSY;
++ goto out_unlock;
++ }
++
++ intf->mode_switch = true;
++ reinit_completion(&intf->mode_switch_completion);
++
++ /*
++ * Get a reference to the interface device, which will be put once the
++ * mode switch is complete.
++ */
++ get_device(&intf->dev);
++
++ if (!queue_work(system_long_wq, &intf->mode_switch_work)) {
++ put_device(&intf->dev);
++ ret = -EBUSY;
++ goto out_unlock;
++ }
++
++out_unlock:
++ mutex_unlock(&intf->mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_interface_request_mode_switch);
++
++/*
++ * T_TstSrcIncrement is written by the module on ES2 as a stand-in for the
++ * init-status attribute DME_TOSHIBA_INIT_STATUS. The AP needs to read and
++ * clear it after reading a non-zero value from it.
++ *
++ * FIXME: This is module-hardware dependent and needs to be extended for every
++ * type of module we want to support.
++ */
++static int gb_interface_read_and_clear_init_status(struct gb_interface *intf)
++{
++ struct gb_host_device *hd = intf->hd;
++ unsigned long bootrom_quirks;
++ unsigned long s2l_quirks;
++ int ret;
++ u32 value;
++ u16 attr;
++ u8 init_status;
++
++ /*
++ * ES2 bridges use T_TstSrcIncrement for the init status.
++ *
++ * FIXME: Remove ES2 support
++ */
++ if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
++ attr = DME_T_TST_SRC_INCREMENT;
++ else
++ attr = DME_TOSHIBA_GMP_INIT_STATUS;
++
++ ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, attr,
++ DME_SELECTOR_INDEX_NULL, &value);
++ if (ret)
++ return ret;
++
++ /*
++ * A nonzero init status indicates the module has finished
++ * initializing.
++ */
++ if (!value) {
++ dev_err(&intf->dev, "invalid init status\n");
++ return -ENODEV;
++ }
++
++ /*
++ * Extract the init status.
++ *
++ * For ES2: We need to check lowest 8 bits of 'value'.
++ * For ES3: We need to check highest 8 bits out of 32 of 'value'.
++ *
++ * FIXME: Remove ES2 support
++ */
++ if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)
++ init_status = value & 0xff;
++ else
++ init_status = value >> 24;
++
++ /*
++ * Check if the interface is executing the quirky ES3 bootrom that,
++ * for example, requires E2EFC, CSD and CSV to be disabled.
++ */
++ bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES |
++ GB_INTERFACE_QUIRK_FORCED_DISABLE |
++ GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH |
++ GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE;
++
++ s2l_quirks = GB_INTERFACE_QUIRK_NO_PM;
++
++ switch (init_status) {
++ case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED:
++ case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED:
++ intf->quirks |= bootrom_quirks;
++ break;
++ case GB_INIT_S2_LOADER_BOOT_STARTED:
++ /* S2 Loader doesn't support runtime PM */
++ intf->quirks &= ~bootrom_quirks;
++ intf->quirks |= s2l_quirks;
++ break;
++ default:
++ intf->quirks &= ~bootrom_quirks;
++ intf->quirks &= ~s2l_quirks;
++ }
++
++ /* Clear the init status. */
++ return gb_svc_dme_peer_set(hd->svc, intf->interface_id, attr,
++ DME_SELECTOR_INDEX_NULL, 0);
++}
++
++/* interface sysfs attributes */
++#define gb_interface_attr(field, type) \
++static ssize_t field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_interface *intf = to_gb_interface(dev); \
++ return scnprintf(buf, PAGE_SIZE, type"\n", intf->field); \
++} \
++static DEVICE_ATTR_RO(field)
++
++gb_interface_attr(ddbl1_manufacturer_id, "0x%08x");
++gb_interface_attr(ddbl1_product_id, "0x%08x");
++gb_interface_attr(interface_id, "%u");
++gb_interface_attr(vendor_id, "0x%08x");
++gb_interface_attr(product_id, "0x%08x");
++gb_interface_attr(serial_number, "0x%016llx");
++
++static ssize_t voltage_now_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ int ret;
++ u32 measurement;
++
++ ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
++ GB_SVC_PWRMON_TYPE_VOL,
++ &measurement);
++ if (ret) {
++ dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret);
++ return ret;
++ }
++
++ return sprintf(buf, "%u\n", measurement);
++}
++static DEVICE_ATTR_RO(voltage_now);
++
++static ssize_t current_now_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ int ret;
++ u32 measurement;
++
++ ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
++ GB_SVC_PWRMON_TYPE_CURR,
++ &measurement);
++ if (ret) {
++ dev_err(&intf->dev, "failed to get current sample (%d)\n", ret);
++ return ret;
++ }
++
++ return sprintf(buf, "%u\n", measurement);
++}
++static DEVICE_ATTR_RO(current_now);
++
++static ssize_t power_now_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ int ret;
++ u32 measurement;
++
++ ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
++ GB_SVC_PWRMON_TYPE_PWR,
++ &measurement);
++ if (ret) {
++ dev_err(&intf->dev, "failed to get power sample (%d)\n", ret);
++ return ret;
++ }
++
++ return sprintf(buf, "%u\n", measurement);
++}
++static DEVICE_ATTR_RO(power_now);
++
++static ssize_t power_state_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ if (intf->active)
++ return scnprintf(buf, PAGE_SIZE, "on\n");
++ else
++ return scnprintf(buf, PAGE_SIZE, "off\n");
++}
++
++static ssize_t power_state_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t len)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ bool activate;
++ int ret = 0;
++
++ if (kstrtobool(buf, &activate))
++ return -EINVAL;
++
++ mutex_lock(&intf->mutex);
++
++ if (activate == intf->active)
++ goto unlock;
++
++ if (activate) {
++ ret = gb_interface_activate(intf);
++ if (ret) {
++ dev_err(&intf->dev,
++ "failed to activate interface: %d\n", ret);
++ goto unlock;
++ }
++
++ ret = gb_interface_enable(intf);
++ if (ret) {
++ dev_err(&intf->dev,
++ "failed to enable interface: %d\n", ret);
++ gb_interface_deactivate(intf);
++ goto unlock;
++ }
++ } else {
++ gb_interface_disable(intf);
++ gb_interface_deactivate(intf);
++ }
++
++unlock:
++ mutex_unlock(&intf->mutex);
++
++ if (ret)
++ return ret;
++
++ return len;
++}
++static DEVICE_ATTR_RW(power_state);
++
++static const char *gb_interface_type_string(struct gb_interface *intf)
++{
++ static const char * const types[] = {
++ [GB_INTERFACE_TYPE_INVALID] = "invalid",
++ [GB_INTERFACE_TYPE_UNKNOWN] = "unknown",
++ [GB_INTERFACE_TYPE_DUMMY] = "dummy",
++ [GB_INTERFACE_TYPE_UNIPRO] = "unipro",
++ [GB_INTERFACE_TYPE_GREYBUS] = "greybus",
++ };
++
++ return types[intf->type];
++}
++
++static ssize_t interface_type_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ return sprintf(buf, "%s\n", gb_interface_type_string(intf));
++}
++static DEVICE_ATTR_RO(interface_type);
++
++static struct attribute *interface_unipro_attrs[] = {
++ &dev_attr_ddbl1_manufacturer_id.attr,
++ &dev_attr_ddbl1_product_id.attr,
++ NULL
++};
++
++static struct attribute *interface_greybus_attrs[] = {
++ &dev_attr_vendor_id.attr,
++ &dev_attr_product_id.attr,
++ &dev_attr_serial_number.attr,
++ NULL
++};
++
++static struct attribute *interface_power_attrs[] = {
++ &dev_attr_voltage_now.attr,
++ &dev_attr_current_now.attr,
++ &dev_attr_power_now.attr,
++ &dev_attr_power_state.attr,
++ NULL
++};
++
++static struct attribute *interface_common_attrs[] = {
++ &dev_attr_interface_id.attr,
++ &dev_attr_interface_type.attr,
++ NULL
++};
++
++static umode_t interface_unipro_is_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ switch (intf->type) {
++ case GB_INTERFACE_TYPE_UNIPRO:
++ case GB_INTERFACE_TYPE_GREYBUS:
++ return attr->mode;
++ default:
++ return 0;
++ }
++}
++
++static umode_t interface_greybus_is_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ switch (intf->type) {
++ case GB_INTERFACE_TYPE_GREYBUS:
++ return attr->mode;
++ default:
++ return 0;
++ }
++}
++
++static umode_t interface_power_is_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ switch (intf->type) {
++ case GB_INTERFACE_TYPE_UNIPRO:
++ case GB_INTERFACE_TYPE_GREYBUS:
++ return attr->mode;
++ default:
++ return 0;
++ }
++}
++
++static const struct attribute_group interface_unipro_group = {
++ .is_visible = interface_unipro_is_visible,
++ .attrs = interface_unipro_attrs,
++};
++
++static const struct attribute_group interface_greybus_group = {
++ .is_visible = interface_greybus_is_visible,
++ .attrs = interface_greybus_attrs,
++};
++
++static const struct attribute_group interface_power_group = {
++ .is_visible = interface_power_is_visible,
++ .attrs = interface_power_attrs,
++};
++
++static const struct attribute_group interface_common_group = {
++ .attrs = interface_common_attrs,
++};
++
++static const struct attribute_group *interface_groups[] = {
++ &interface_unipro_group,
++ &interface_greybus_group,
++ &interface_power_group,
++ &interface_common_group,
++ NULL
++};
++
++static void gb_interface_release(struct device *dev)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++
++ trace_gb_interface_release(intf);
++
++ kfree(intf);
++}
++
++#ifdef CONFIG_PM
++static int gb_interface_suspend(struct device *dev)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ int ret, timesync_ret;
++
++ ret = gb_control_interface_suspend_prepare(intf->control);
++ if (ret)
++ return ret;
++
++ gb_timesync_interface_remove(intf);
++
++ ret = gb_control_suspend(intf->control);
++ if (ret)
++ goto err_hibernate_abort;
++
++ ret = gb_interface_hibernate_link(intf);
++ if (ret)
++ return ret;
++
++ /* Delay to allow interface to enter standby before disabling refclk */
++ msleep(GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS);
++
++ ret = gb_interface_refclk_set(intf, false);
++ if (ret)
++ return ret;
++
++ return 0;
++
++err_hibernate_abort:
++ gb_control_interface_hibernate_abort(intf->control);
++
++ timesync_ret = gb_timesync_interface_add(intf);
++ if (timesync_ret) {
++ dev_err(dev, "failed to add to timesync: %d\n", timesync_ret);
++ return timesync_ret;
++ }
++
++ return ret;
++}
++
++static int gb_interface_resume(struct device *dev)
++{
++ struct gb_interface *intf = to_gb_interface(dev);
++ struct gb_svc *svc = intf->hd->svc;
++ int ret;
++
++ ret = gb_interface_refclk_set(intf, true);
++ if (ret)
++ return ret;
++
++ ret = gb_svc_intf_resume(svc, intf->interface_id);
++ if (ret)
++ return ret;
++
++ ret = gb_control_resume(intf->control);
++ if (ret)
++ return ret;
++
++ ret = gb_timesync_interface_add(intf);
++ if (ret) {
++ dev_err(dev, "failed to add to timesync: %d\n", ret);
++ return ret;
++ }
++
++ ret = gb_timesync_schedule_synchronous(intf);
++ if (ret) {
++ dev_err(dev, "failed to synchronize FrameTime: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_interface_runtime_idle(struct device *dev)
++{
++ pm_runtime_mark_last_busy(dev);
++ pm_request_autosuspend(dev);
++
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops gb_interface_pm_ops = {
++ SET_RUNTIME_PM_OPS(gb_interface_suspend, gb_interface_resume,
++ gb_interface_runtime_idle)
++};
++
++struct device_type greybus_interface_type = {
++ .name = "greybus_interface",
++ .release = gb_interface_release,
++ .pm = &gb_interface_pm_ops,
++};
++
++/*
++ * A Greybus module represents a user-replaceable component on a GMP
++ * phone. An interface is the physical connection on that module. A
++ * module may have more than one interface.
++ *
++ * Create a gb_interface structure to represent a discovered interface.
++ * The position of interface within the Endo is encoded in "interface_id"
++ * argument.
++ *
++ * Returns a pointer to the new interfce or a null pointer if a
++ * failure occurs due to memory exhaustion.
++ */
++struct gb_interface *gb_interface_create(struct gb_module *module,
++ u8 interface_id)
++{
++ struct gb_host_device *hd = module->hd;
++ struct gb_interface *intf;
++
++ intf = kzalloc(sizeof(*intf), GFP_KERNEL);
++ if (!intf)
++ return NULL;
++
++ intf->hd = hd; /* XXX refcount? */
++ intf->module = module;
++ intf->interface_id = interface_id;
++ INIT_LIST_HEAD(&intf->bundles);
++ INIT_LIST_HEAD(&intf->manifest_descs);
++ mutex_init(&intf->mutex);
++ INIT_WORK(&intf->mode_switch_work, gb_interface_mode_switch_work);
++ init_completion(&intf->mode_switch_completion);
++
++ /* Invalid device id to start with */
++ intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
++
++ intf->dev.parent = &module->dev;
++ intf->dev.bus = &greybus_bus_type;
++ intf->dev.type = &greybus_interface_type;
++ intf->dev.groups = interface_groups;
++ intf->dev.dma_mask = module->dev.dma_mask;
++ device_initialize(&intf->dev);
++ dev_set_name(&intf->dev, "%s.%u", dev_name(&module->dev),
++ interface_id);
++
++ pm_runtime_set_autosuspend_delay(&intf->dev,
++ GB_INTERFACE_AUTOSUSPEND_MS);
++
++ trace_gb_interface_create(intf);
++
++ return intf;
++}
++
++static int gb_interface_vsys_set(struct gb_interface *intf, bool enable)
++{
++ struct gb_svc *svc = intf->hd->svc;
++ int ret;
++
++ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
++
++ ret = gb_svc_intf_vsys_set(svc, intf->interface_id, enable);
++ if (ret) {
++ dev_err(&intf->dev, "failed to set v_sys: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_interface_refclk_set(struct gb_interface *intf, bool enable)
++{
++ struct gb_svc *svc = intf->hd->svc;
++ int ret;
++
++ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
++
++ ret = gb_svc_intf_refclk_set(svc, intf->interface_id, enable);
++ if (ret) {
++ dev_err(&intf->dev, "failed to set refclk: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_interface_unipro_set(struct gb_interface *intf, bool enable)
++{
++ struct gb_svc *svc = intf->hd->svc;
++ int ret;
++
++ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
++
++ ret = gb_svc_intf_unipro_set(svc, intf->interface_id, enable);
++ if (ret) {
++ dev_err(&intf->dev, "failed to set UniPro: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_interface_activate_operation(struct gb_interface *intf,
++ enum gb_interface_type *intf_type)
++{
++ struct gb_svc *svc = intf->hd->svc;
++ u8 type;
++ int ret;
++
++ dev_dbg(&intf->dev, "%s\n", __func__);
++
++ ret = gb_svc_intf_activate(svc, intf->interface_id, &type);
++ if (ret) {
++ dev_err(&intf->dev, "failed to activate: %d\n", ret);
++ return ret;
++ }
++
++ switch (type) {
++ case GB_SVC_INTF_TYPE_DUMMY:
++ *intf_type = GB_INTERFACE_TYPE_DUMMY;
++ /* FIXME: handle as an error for now */
++ return -ENODEV;
++ case GB_SVC_INTF_TYPE_UNIPRO:
++ *intf_type = GB_INTERFACE_TYPE_UNIPRO;
++ dev_err(&intf->dev, "interface type UniPro not supported\n");
++ /* FIXME: handle as an error for now */
++ return -ENODEV;
++ case GB_SVC_INTF_TYPE_GREYBUS:
++ *intf_type = GB_INTERFACE_TYPE_GREYBUS;
++ break;
++ default:
++ dev_err(&intf->dev, "unknown interface type: %u\n", type);
++ *intf_type = GB_INTERFACE_TYPE_UNKNOWN;
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int gb_interface_hibernate_link(struct gb_interface *intf)
++{
++ struct gb_svc *svc = intf->hd->svc;
++
++ return gb_svc_intf_set_power_mode_hibernate(svc, intf->interface_id);
++}
++
++static int _gb_interface_activate(struct gb_interface *intf,
++ enum gb_interface_type *type)
++{
++ int ret;
++
++ *type = GB_INTERFACE_TYPE_UNKNOWN;
++
++ if (intf->ejected || intf->removed)
++ return -ENODEV;
++
++ ret = gb_interface_vsys_set(intf, true);
++ if (ret)
++ return ret;
++
++ ret = gb_interface_refclk_set(intf, true);
++ if (ret)
++ goto err_vsys_disable;
++
++ ret = gb_interface_unipro_set(intf, true);
++ if (ret)
++ goto err_refclk_disable;
++
++ ret = gb_interface_activate_operation(intf, type);
++ if (ret) {
++ switch (*type) {
++ case GB_INTERFACE_TYPE_UNIPRO:
++ case GB_INTERFACE_TYPE_GREYBUS:
++ goto err_hibernate_link;
++ default:
++ goto err_unipro_disable;
++ }
++ }
++
++ ret = gb_interface_read_dme(intf);
++ if (ret)
++ goto err_hibernate_link;
++
++ ret = gb_interface_route_create(intf);
++ if (ret)
++ goto err_hibernate_link;
++
++ intf->active = true;
++
++ trace_gb_interface_activate(intf);
++
++ return 0;
++
++err_hibernate_link:
++ gb_interface_hibernate_link(intf);
++err_unipro_disable:
++ gb_interface_unipro_set(intf, false);
++err_refclk_disable:
++ gb_interface_refclk_set(intf, false);
++err_vsys_disable:
++ gb_interface_vsys_set(intf, false);
++
++ return ret;
++}
++
++/*
++ * At present, we assume a UniPro-only module to be a Greybus module that
++ * failed to send its mailbox poke. There is some reason to believe that this
++ * is because of a bug in the ES3 bootrom.
++ *
++ * FIXME: Check if this is a Toshiba bridge before retrying?
++ */
++static int _gb_interface_activate_es3_hack(struct gb_interface *intf,
++ enum gb_interface_type *type)
++{
++ int retries = 3;
++ int ret;
++
++ while (retries--) {
++ ret = _gb_interface_activate(intf, type);
++ if (ret == -ENODEV && *type == GB_INTERFACE_TYPE_UNIPRO)
++ continue;
++
++ break;
++ }
++
++ return ret;
++}
++
++/*
++ * Activate an interface.
++ *
++ * Locking: Caller holds the interface mutex.
++ */
++int gb_interface_activate(struct gb_interface *intf)
++{
++ enum gb_interface_type type;
++ int ret;
++
++ switch (intf->type) {
++ case GB_INTERFACE_TYPE_INVALID:
++ case GB_INTERFACE_TYPE_GREYBUS:
++ ret = _gb_interface_activate_es3_hack(intf, &type);
++ break;
++ default:
++ ret = _gb_interface_activate(intf, &type);
++ }
++
++ /* Make sure type is detected correctly during reactivation. */
++ if (intf->type != GB_INTERFACE_TYPE_INVALID) {
++ if (type != intf->type) {
++ dev_err(&intf->dev, "failed to detect interface type\n");
++
++ if (!ret)
++ gb_interface_deactivate(intf);
++
++ return -EIO;
++ }
++ } else {
++ intf->type = type;
++ }
++
++ return ret;
++}
++
++/*
++ * Deactivate an interface.
++ *
++ * Locking: Caller holds the interface mutex.
++ */
++void gb_interface_deactivate(struct gb_interface *intf)
++{
++ if (!intf->active)
++ return;
++
++ trace_gb_interface_deactivate(intf);
++
++ /* Abort any ongoing mode switch. */
++ if (intf->mode_switch)
++ complete(&intf->mode_switch_completion);
++
++ gb_interface_route_destroy(intf);
++ gb_interface_hibernate_link(intf);
++ gb_interface_unipro_set(intf, false);
++ gb_interface_refclk_set(intf, false);
++ gb_interface_vsys_set(intf, false);
++
++ intf->active = false;
++}
++
++/*
++ * Enable an interface by enabling its control connection, fetching the
++ * manifest and other information over it, and finally registering its child
++ * devices.
++ *
++ * Locking: Caller holds the interface mutex.
++ */
++int gb_interface_enable(struct gb_interface *intf)
++{
++ struct gb_control *control;
++ struct gb_bundle *bundle, *tmp;
++ int ret, size;
++ void *manifest;
++
++ ret = gb_interface_read_and_clear_init_status(intf);
++ if (ret) {
++ dev_err(&intf->dev, "failed to clear init status: %d\n", ret);
++ return ret;
++ }
++
++ /* Establish control connection */
++ control = gb_control_create(intf);
++ if (IS_ERR(control)) {
++ dev_err(&intf->dev, "failed to create control device: %ld\n",
++ PTR_ERR(control));
++ return PTR_ERR(control);
++ }
++ intf->control = control;
++
++ ret = gb_control_enable(intf->control);
++ if (ret)
++ goto err_put_control;
++
++ /* Get manifest size using control protocol on CPort */
++ size = gb_control_get_manifest_size_operation(intf);
++ if (size <= 0) {
++ dev_err(&intf->dev, "failed to get manifest size: %d\n", size);
++
++ if (size)
++ ret = size;
++ else
++ ret = -EINVAL;
++
++ goto err_disable_control;
++ }
++
++ manifest = kmalloc(size, GFP_KERNEL);
++ if (!manifest) {
++ ret = -ENOMEM;
++ goto err_disable_control;
++ }
++
++ /* Get manifest using control protocol on CPort */
++ ret = gb_control_get_manifest_operation(intf, manifest, size);
++ if (ret) {
++ dev_err(&intf->dev, "failed to get manifest: %d\n", ret);
++ goto err_free_manifest;
++ }
++
++ /*
++ * Parse the manifest and build up our data structures representing
++ * what's in it.
++ */
++ if (!gb_manifest_parse(intf, manifest, size)) {
++ dev_err(&intf->dev, "failed to parse manifest\n");
++ ret = -EINVAL;
++ goto err_destroy_bundles;
++ }
++
++ ret = gb_control_get_bundle_versions(intf->control);
++ if (ret)
++ goto err_destroy_bundles;
++
++ ret = gb_timesync_interface_add(intf);
++ if (ret) {
++ dev_err(&intf->dev, "failed to add to timesync: %d\n", ret);
++ goto err_destroy_bundles;
++ }
++
++ /* Register the control device and any bundles */
++ ret = gb_control_add(intf->control);
++ if (ret)
++ goto err_remove_timesync;
++
++ pm_runtime_use_autosuspend(&intf->dev);
++ pm_runtime_get_noresume(&intf->dev);
++ pm_runtime_set_active(&intf->dev);
++ pm_runtime_enable(&intf->dev);
++
++ list_for_each_entry_safe_reverse(bundle, tmp, &intf->bundles, links) {
++ ret = gb_bundle_add(bundle);
++ if (ret) {
++ gb_bundle_destroy(bundle);
++ continue;
++ }
++ }
++
++ kfree(manifest);
++
++ intf->enabled = true;
++
++ pm_runtime_put(&intf->dev);
++
++ trace_gb_interface_enable(intf);
++
++ return 0;
++
++err_remove_timesync:
++ gb_timesync_interface_remove(intf);
++err_destroy_bundles:
++ list_for_each_entry_safe(bundle, tmp, &intf->bundles, links)
++ gb_bundle_destroy(bundle);
++err_free_manifest:
++ kfree(manifest);
++err_disable_control:
++ gb_control_disable(intf->control);
++err_put_control:
++ gb_control_put(intf->control);
++ intf->control = NULL;
++
++ return ret;
++}
++
++/*
++ * Disable an interface and destroy its bundles.
++ *
++ * Locking: Caller holds the interface mutex.
++ */
++void gb_interface_disable(struct gb_interface *intf)
++{
++ struct gb_bundle *bundle;
++ struct gb_bundle *next;
++
++ if (!intf->enabled)
++ return;
++
++ trace_gb_interface_disable(intf);
++
++ pm_runtime_get_sync(&intf->dev);
++
++ /* Set disconnected flag to avoid I/O during connection tear down. */
++ if (intf->quirks & GB_INTERFACE_QUIRK_FORCED_DISABLE)
++ intf->disconnected = true;
++
++ list_for_each_entry_safe(bundle, next, &intf->bundles, links)
++ gb_bundle_destroy(bundle);
++
++ if (!intf->mode_switch && !intf->disconnected)
++ gb_control_interface_deactivate_prepare(intf->control);
++
++ gb_control_del(intf->control);
++ gb_timesync_interface_remove(intf);
++ gb_control_disable(intf->control);
++ gb_control_put(intf->control);
++ intf->control = NULL;
++
++ intf->enabled = false;
++
++ pm_runtime_disable(&intf->dev);
++ pm_runtime_set_suspended(&intf->dev);
++ pm_runtime_dont_use_autosuspend(&intf->dev);
++ pm_runtime_put_noidle(&intf->dev);
++}
++
++/* Enable TimeSync on an Interface control connection. */
++int gb_interface_timesync_enable(struct gb_interface *intf, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk)
++{
++ return gb_control_timesync_enable(intf->control, count,
++ frame_time, strobe_delay,
++ refclk);
++}
++
++/* Disable TimeSync on an Interface control connection. */
++int gb_interface_timesync_disable(struct gb_interface *intf)
++{
++ return gb_control_timesync_disable(intf->control);
++}
++
++/* Transmit the Authoritative FrameTime via an Interface control connection. */
++int gb_interface_timesync_authoritative(struct gb_interface *intf,
++ u64 *frame_time)
++{
++ return gb_control_timesync_authoritative(intf->control,
++ frame_time);
++}
++
++/* Register an interface. */
++int gb_interface_add(struct gb_interface *intf)
++{
++ int ret;
++
++ ret = device_add(&intf->dev);
++ if (ret) {
++ dev_err(&intf->dev, "failed to register interface: %d\n", ret);
++ return ret;
++ }
++
++ trace_gb_interface_add(intf);
++
++ dev_info(&intf->dev, "Interface added (%s)\n",
++ gb_interface_type_string(intf));
++
++ switch (intf->type) {
++ case GB_INTERFACE_TYPE_GREYBUS:
++ dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n",
++ intf->vendor_id, intf->product_id);
++ /* fall-through */
++ case GB_INTERFACE_TYPE_UNIPRO:
++ dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n",
++ intf->ddbl1_manufacturer_id,
++ intf->ddbl1_product_id);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++/* Deregister an interface. */
++void gb_interface_del(struct gb_interface *intf)
++{
++ if (device_is_registered(&intf->dev)) {
++ trace_gb_interface_del(intf);
++
++ device_del(&intf->dev);
++ dev_info(&intf->dev, "Interface removed\n");
++ }
++}
++
++void gb_interface_put(struct gb_interface *intf)
++{
++ put_device(&intf->dev);
++}
+--- /dev/null
++++ b/drivers/greybus/interface.h
+@@ -0,0 +1,88 @@
++/*
++ * Greybus Interface Block code
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __INTERFACE_H
++#define __INTERFACE_H
++
++enum gb_interface_type {
++ GB_INTERFACE_TYPE_INVALID = 0,
++ GB_INTERFACE_TYPE_UNKNOWN,
++ GB_INTERFACE_TYPE_DUMMY,
++ GB_INTERFACE_TYPE_UNIPRO,
++ GB_INTERFACE_TYPE_GREYBUS,
++};
++
++#define GB_INTERFACE_QUIRK_NO_CPORT_FEATURES BIT(0)
++#define GB_INTERFACE_QUIRK_NO_INIT_STATUS BIT(1)
++#define GB_INTERFACE_QUIRK_NO_GMP_IDS BIT(2)
++#define GB_INTERFACE_QUIRK_FORCED_DISABLE BIT(3)
++#define GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH BIT(4)
++#define GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE BIT(5)
++#define GB_INTERFACE_QUIRK_NO_PM BIT(6)
++
++struct gb_interface {
++ struct device dev;
++ struct gb_control *control;
++
++ struct list_head bundles;
++ struct list_head module_node;
++ struct list_head manifest_descs;
++ u8 interface_id; /* Physical location within the Endo */
++ u8 device_id;
++ u8 features; /* Feature flags set in the manifest */
++
++ enum gb_interface_type type;
++
++ u32 ddbl1_manufacturer_id;
++ u32 ddbl1_product_id;
++ u32 vendor_id;
++ u32 product_id;
++ u64 serial_number;
++
++ struct gb_host_device *hd;
++ struct gb_module *module;
++
++ unsigned long quirks;
++
++ struct mutex mutex;
++
++ bool disconnected;
++
++ bool ejected;
++ bool removed;
++ bool active;
++ bool enabled;
++ bool mode_switch;
++ bool dme_read;
++
++ struct work_struct mode_switch_work;
++ struct completion mode_switch_completion;
++};
++#define to_gb_interface(d) container_of(d, struct gb_interface, dev)
++
++struct gb_interface *gb_interface_create(struct gb_module *module,
++ u8 interface_id);
++int gb_interface_activate(struct gb_interface *intf);
++void gb_interface_deactivate(struct gb_interface *intf);
++int gb_interface_enable(struct gb_interface *intf);
++void gb_interface_disable(struct gb_interface *intf);
++int gb_interface_timesync_enable(struct gb_interface *intf, u8 count,
++ u64 frame_time, u32 strobe_delay, u32 refclk);
++int gb_interface_timesync_authoritative(struct gb_interface *intf,
++ u64 *frame_time);
++int gb_interface_timesync_disable(struct gb_interface *intf);
++int gb_interface_add(struct gb_interface *intf);
++void gb_interface_del(struct gb_interface *intf);
++void gb_interface_put(struct gb_interface *intf);
++void gb_interface_mailbox_event(struct gb_interface *intf, u16 result,
++ u32 mailbox);
++
++int gb_interface_request_mode_switch(struct gb_interface *intf);
++
++#endif /* __INTERFACE_H */
diff --git a/greybus_light.patch b/greybus_light.patch
new file mode 100644
index 00000000000000..152c14ce826f62
--- /dev/null
+++ b/greybus_light.patch
@@ -0,0 +1,1366 @@
+---
+ drivers/greybus/light.c | 1359 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1359 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/light.c
+@@ -0,0 +1,1359 @@
++/*
++ * Greybus Lights protocol driver.
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/led-class-flash.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/version.h>
++#include <media/v4l2-flash-led-class.h>
++
++#include "greybus.h"
++#include "greybus_protocols.h"
++
++#define NAMES_MAX 32
++
++struct gb_channel {
++ u8 id;
++ u32 flags;
++ u32 color;
++ char *color_name;
++ u8 fade_in;
++ u8 fade_out;
++ u32 mode;
++ char *mode_name;
++ struct attribute **attrs;
++ struct attribute_group *attr_group;
++ const struct attribute_group **attr_groups;
++ struct led_classdev *led;
++#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
++ struct led_classdev_flash fled;
++ struct led_flash_setting intensity_uA;
++ struct led_flash_setting timeout_us;
++#else
++ struct led_classdev cled;
++#endif
++ struct gb_light *light;
++ bool is_registered;
++ bool releasing;
++ bool strobe_state;
++ bool active;
++ struct mutex lock;
++};
++
++struct gb_light {
++ u8 id;
++ char *name;
++ struct gb_lights *glights;
++ u32 flags;
++ u8 channels_count;
++ struct gb_channel *channels;
++ bool has_flash;
++ bool ready;
++#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS)
++ struct v4l2_flash *v4l2_flash;
++#endif
++};
++
++struct gb_lights {
++ struct gb_connection *connection;
++ u8 lights_count;
++ struct gb_light *lights;
++ struct mutex lights_lock;
++};
++
++static void gb_lights_channel_free(struct gb_channel *channel);
++
++static struct gb_connection *get_conn_from_channel(struct gb_channel *channel)
++{
++ return channel->light->glights->connection;
++}
++
++static struct gb_connection *get_conn_from_light(struct gb_light *light)
++{
++ return light->glights->connection;
++}
++
++static bool is_channel_flash(struct gb_channel *channel)
++{
++ return !!(channel->mode & (GB_CHANNEL_MODE_FLASH | GB_CHANNEL_MODE_TORCH
++ | GB_CHANNEL_MODE_INDICATOR));
++}
++
++#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
++static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev)
++{
++ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev);
++
++ return container_of(fled_cdev, struct gb_channel, fled);
++}
++
++static struct led_classdev *get_channel_cdev(struct gb_channel *channel)
++{
++ return &channel->fled.led_cdev;
++}
++
++static struct gb_channel *get_channel_from_mode(struct gb_light *light,
++ u32 mode)
++{
++ struct gb_channel *channel = NULL;
++ int i;
++
++ for (i = 0; i < light->channels_count; i++) {
++ channel = &light->channels[i];
++ if (channel && channel->mode == mode)
++ break;
++ }
++ return channel;
++}
++
++static int __gb_lights_flash_intensity_set(struct gb_channel *channel,
++ u32 intensity)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_set_flash_intensity_request req;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.intensity_uA = cpu_to_le32(intensity);
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_INTENSITY,
++ &req, sizeof(req), NULL, 0);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int __gb_lights_flash_brightness_set(struct gb_channel *channel)
++{
++ u32 intensity;
++
++ /* If the channel is flash we need to get the attached torch channel */
++ if (channel->mode & GB_CHANNEL_MODE_FLASH)
++ channel = get_channel_from_mode(channel->light,
++ GB_CHANNEL_MODE_TORCH);
++
++ /* For not flash we need to convert brightness to intensity */
++ intensity = channel->intensity_uA.min +
++ (channel->intensity_uA.step * channel->led->brightness);
++
++ return __gb_lights_flash_intensity_set(channel, intensity);
++}
++#else
++static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev)
++{
++ return container_of(cdev, struct gb_channel, cled);
++}
++
++static struct led_classdev *get_channel_cdev(struct gb_channel *channel)
++{
++ return &channel->cled;
++}
++
++static int __gb_lights_flash_brightness_set(struct gb_channel *channel)
++{
++ return 0;
++}
++#endif
++
++static int gb_lights_color_set(struct gb_channel *channel, u32 color);
++static int gb_lights_fade_set(struct gb_channel *channel);
++
++static void led_lock(struct led_classdev *cdev)
++{
++ mutex_lock(&cdev->led_access);
++}
++
++static void led_unlock(struct led_classdev *cdev)
++{
++ mutex_unlock(&cdev->led_access);
++}
++
++#define gb_lights_fade_attr(__dir) \
++static ssize_t fade_##__dir##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct led_classdev *cdev = dev_get_drvdata(dev); \
++ struct gb_channel *channel = get_channel_from_cdev(cdev); \
++ \
++ return sprintf(buf, "%u\n", channel->fade_##__dir); \
++} \
++ \
++static ssize_t fade_##__dir##_store(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t size) \
++{ \
++ struct led_classdev *cdev = dev_get_drvdata(dev); \
++ struct gb_channel *channel = get_channel_from_cdev(cdev); \
++ u8 fade; \
++ int ret; \
++ \
++ led_lock(cdev); \
++ if (led_sysfs_is_disabled(cdev)) { \
++ ret = -EBUSY; \
++ goto unlock; \
++ } \
++ \
++ ret = kstrtou8(buf, 0, &fade); \
++ if (ret < 0) { \
++ dev_err(dev, "could not parse fade value %d\n", ret); \
++ goto unlock; \
++ } \
++ if (channel->fade_##__dir == fade) \
++ goto unlock; \
++ channel->fade_##__dir = fade; \
++ \
++ ret = gb_lights_fade_set(channel); \
++ if (ret < 0) \
++ goto unlock; \
++ \
++ ret = size; \
++unlock: \
++ led_unlock(cdev); \
++ return ret; \
++} \
++static DEVICE_ATTR_RW(fade_##__dir)
++
++gb_lights_fade_attr(in);
++gb_lights_fade_attr(out);
++
++static ssize_t color_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct led_classdev *cdev = dev_get_drvdata(dev);
++ struct gb_channel *channel = get_channel_from_cdev(cdev);
++
++ return sprintf(buf, "0x%08x\n", channel->color);
++}
++
++static ssize_t color_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct led_classdev *cdev = dev_get_drvdata(dev);
++ struct gb_channel *channel = get_channel_from_cdev(cdev);
++ u32 color;
++ int ret;
++
++ led_lock(cdev);
++ if (led_sysfs_is_disabled(cdev)) {
++ ret = -EBUSY;
++ goto unlock;
++ }
++ ret = kstrtou32(buf, 0, &color);
++ if (ret < 0) {
++ dev_err(dev, "could not parse color value %d\n", ret);
++ goto unlock;
++ }
++
++ ret = gb_lights_color_set(channel, color);
++ if (ret < 0)
++ goto unlock;
++
++ channel->color = color;
++ ret = size;
++unlock:
++ led_unlock(cdev);
++ return ret;
++}
++static DEVICE_ATTR_RW(color);
++
++static int channel_attr_groups_set(struct gb_channel *channel,
++ struct led_classdev *cdev)
++{
++ int attr = 0;
++ int size = 0;
++
++ if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR)
++ size++;
++ if (channel->flags & GB_LIGHT_CHANNEL_FADER)
++ size += 2;
++
++ if (!size)
++ return 0;
++
++ /* Set attributes based in the channel flags */
++ channel->attrs = kcalloc(size + 1, sizeof(**channel->attrs),
++ GFP_KERNEL);
++ if (!channel->attrs)
++ return -ENOMEM;
++ channel->attr_group = kcalloc(1, sizeof(*channel->attr_group),
++ GFP_KERNEL);
++ if (!channel->attr_group)
++ return -ENOMEM;
++ channel->attr_groups = kcalloc(2, sizeof(*channel->attr_groups),
++ GFP_KERNEL);
++ if (!channel->attr_groups)
++ return -ENOMEM;
++
++ if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR)
++ channel->attrs[attr++] = &dev_attr_color.attr;
++ if (channel->flags & GB_LIGHT_CHANNEL_FADER) {
++ channel->attrs[attr++] = &dev_attr_fade_in.attr;
++ channel->attrs[attr++] = &dev_attr_fade_out.attr;
++ }
++
++ channel->attr_group->attrs = channel->attrs;
++
++ channel->attr_groups[0] = channel->attr_group;
++
++ cdev->groups = channel->attr_groups;
++
++ return 0;
++}
++
++static int gb_lights_fade_set(struct gb_channel *channel)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_set_fade_request req;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.fade_in = channel->fade_in;
++ req.fade_out = channel->fade_out;
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FADE,
++ &req, sizeof(req), NULL, 0);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int gb_lights_color_set(struct gb_channel *channel, u32 color)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_set_color_request req;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.color = cpu_to_le32(color);
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_COLOR,
++ &req, sizeof(req), NULL, 0);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int __gb_lights_led_brightness_set(struct gb_channel *channel)
++{
++ struct gb_lights_set_brightness_request req;
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ bool old_active;
++ int ret;
++
++ mutex_lock(&channel->lock);
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ goto out_unlock;
++
++ old_active = channel->active;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.brightness = (u8)channel->led->brightness;
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BRIGHTNESS,
++ &req, sizeof(req), NULL, 0);
++ if (ret < 0)
++ goto out_pm_put;
++
++ if (channel->led->brightness)
++ channel->active = true;
++ else
++ channel->active = false;
++
++ /* we need to keep module alive when turning to active state */
++ if (!old_active && channel->active)
++ goto out_unlock;
++
++ /*
++ * on the other hand if going to inactive we still hold a reference and
++ * need to put it, so we could go to suspend.
++ */
++ if (old_active && !channel->active)
++ gb_pm_runtime_put_autosuspend(bundle);
++
++out_pm_put:
++ gb_pm_runtime_put_autosuspend(bundle);
++out_unlock:
++ mutex_unlock(&channel->lock);
++
++ return ret;
++}
++
++static int __gb_lights_brightness_set(struct gb_channel *channel)
++{
++ int ret;
++
++ if (channel->releasing)
++ return 0;
++
++ if (is_channel_flash(channel))
++ ret = __gb_lights_flash_brightness_set(channel);
++ else
++ ret = __gb_lights_led_brightness_set(channel);
++
++ return ret;
++}
++
++static int gb_brightness_set(struct led_classdev *cdev,
++ enum led_brightness value)
++{
++ struct gb_channel *channel = get_channel_from_cdev(cdev);
++
++ channel->led->brightness = value;
++
++ return __gb_lights_brightness_set(channel);
++}
++
++static enum led_brightness gb_brightness_get(struct led_classdev *cdev)
++
++{
++ struct gb_channel *channel = get_channel_from_cdev(cdev);
++
++ return channel->led->brightness;
++}
++
++static int gb_blink_set(struct led_classdev *cdev, unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ struct gb_channel *channel = get_channel_from_cdev(cdev);
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_blink_request req;
++ bool old_active;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ mutex_lock(&channel->lock);
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ goto out_unlock;
++
++ old_active = channel->active;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.time_on_ms = cpu_to_le16(*delay_on);
++ req.time_off_ms = cpu_to_le16(*delay_off);
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BLINK, &req,
++ sizeof(req), NULL, 0);
++ if (ret < 0)
++ goto out_pm_put;
++
++ if (delay_on)
++ channel->active = true;
++ else
++ channel->active = false;
++
++ /* we need to keep module alive when turning to active state */
++ if (!old_active && channel->active)
++ goto out_unlock;
++
++ /*
++ * on the other hand if going to inactive we still hold a reference and
++ * need to put it, so we could go to suspend.
++ */
++ if (old_active && !channel->active)
++ gb_pm_runtime_put_autosuspend(bundle);
++
++out_pm_put:
++ gb_pm_runtime_put_autosuspend(bundle);
++out_unlock:
++ mutex_unlock(&channel->lock);
++
++ return ret;
++}
++
++static void gb_lights_led_operations_set(struct gb_channel *channel,
++ struct led_classdev *cdev)
++{
++ cdev->brightness_get = gb_brightness_get;
++ cdev->brightness_set_blocking = gb_brightness_set;
++
++ if (channel->flags & GB_LIGHT_CHANNEL_BLINK)
++ cdev->blink_set = gb_blink_set;
++}
++
++#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS)
++/* V4L2 specific helpers */
++static const struct v4l2_flash_ops v4l2_flash_ops;
++
++static void __gb_lights_channel_v4l2_config(struct led_flash_setting *channel_s,
++ struct led_flash_setting *v4l2_s)
++{
++ v4l2_s->min = channel_s->min;
++ v4l2_s->max = channel_s->max;
++ v4l2_s->step = channel_s->step;
++ /* For v4l2 val is the default value */
++ v4l2_s->val = channel_s->max;
++}
++
++static int gb_lights_light_v4l2_register(struct gb_light *light)
++{
++ struct gb_connection *connection = get_conn_from_light(light);
++ struct device *dev = &connection->bundle->dev;
++ struct v4l2_flash_config *sd_cfg;
++ struct led_classdev_flash *fled;
++ struct led_classdev_flash *iled = NULL;
++ struct gb_channel *channel_torch, *channel_ind, *channel_flash;
++ int ret = 0;
++
++ sd_cfg = kcalloc(1, sizeof(*sd_cfg), GFP_KERNEL);
++ if (!sd_cfg)
++ return -ENOMEM;
++
++ channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH);
++ if (channel_torch)
++ __gb_lights_channel_v4l2_config(&channel_torch->intensity_uA,
++ &sd_cfg->torch_intensity);
++
++ channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR);
++ if (channel_ind) {
++ __gb_lights_channel_v4l2_config(&channel_ind->intensity_uA,
++ &sd_cfg->indicator_intensity);
++ iled = &channel_ind->fled;
++ }
++
++ channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH);
++ WARN_ON(!channel_flash);
++
++ fled = &channel_flash->fled;
++
++ snprintf(sd_cfg->dev_name, sizeof(sd_cfg->dev_name), "%s", light->name);
++
++ /* Set the possible values to faults, in our case all faults */
++ sd_cfg->flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT |
++ LED_FAULT_OVER_TEMPERATURE | LED_FAULT_SHORT_CIRCUIT |
++ LED_FAULT_OVER_CURRENT | LED_FAULT_INDICATOR |
++ LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE |
++ LED_FAULT_LED_OVER_TEMPERATURE;
++
++ light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, iled,
++ &v4l2_flash_ops, sd_cfg);
++ if (IS_ERR_OR_NULL(light->v4l2_flash)) {
++ ret = PTR_ERR(light->v4l2_flash);
++ goto out_free;
++ }
++
++ return ret;
++
++out_free:
++ kfree(sd_cfg);
++ return ret;
++}
++
++static void gb_lights_light_v4l2_unregister(struct gb_light *light)
++{
++ v4l2_flash_release(light->v4l2_flash);
++}
++#else
++static int gb_lights_light_v4l2_register(struct gb_light *light)
++{
++ struct gb_connection *connection = get_conn_from_light(light);
++
++ dev_err(&connection->bundle->dev, "no support for v4l2 subdevices\n");
++ return 0;
++}
++
++static void gb_lights_light_v4l2_unregister(struct gb_light *light)
++{
++}
++#endif
++
++#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
++/* Flash specific operations */
++static int gb_lights_flash_intensity_set(struct led_classdev_flash *fcdev,
++ u32 brightness)
++{
++ struct gb_channel *channel = container_of(fcdev, struct gb_channel,
++ fled);
++ int ret;
++
++ ret = __gb_lights_flash_intensity_set(channel, brightness);
++ if (ret < 0)
++ return ret;
++
++ fcdev->brightness.val = brightness;
++
++ return 0;
++}
++
++static int gb_lights_flash_intensity_get(struct led_classdev_flash *fcdev,
++ u32 *brightness)
++{
++ *brightness = fcdev->brightness.val;
++
++ return 0;
++}
++
++static int gb_lights_flash_strobe_set(struct led_classdev_flash *fcdev,
++ bool state)
++{
++ struct gb_channel *channel = container_of(fcdev, struct gb_channel,
++ fled);
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_set_flash_strobe_request req;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.state = state ? 1 : 0;
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_STROBE,
++ &req, sizeof(req), NULL, 0);
++ if (!ret)
++ channel->strobe_state = state;
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int gb_lights_flash_strobe_get(struct led_classdev_flash *fcdev,
++ bool *state)
++{
++ struct gb_channel *channel = container_of(fcdev, struct gb_channel,
++ fled);
++
++ *state = channel->strobe_state;
++ return 0;
++}
++
++static int gb_lights_flash_timeout_set(struct led_classdev_flash *fcdev,
++ u32 timeout)
++{
++ struct gb_channel *channel = container_of(fcdev, struct gb_channel,
++ fled);
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_set_flash_timeout_request req;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++ req.timeout_us = cpu_to_le32(timeout);
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT,
++ &req, sizeof(req), NULL, 0);
++ if (!ret)
++ fcdev->timeout.val = timeout;
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int gb_lights_flash_fault_get(struct led_classdev_flash *fcdev,
++ u32 *fault)
++{
++ struct gb_channel *channel = container_of(fcdev, struct gb_channel,
++ fled);
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_bundle *bundle = connection->bundle;
++ struct gb_lights_get_flash_fault_request req;
++ struct gb_lights_get_flash_fault_response resp;
++ int ret;
++
++ if (channel->releasing)
++ return -ESHUTDOWN;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret < 0)
++ return ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_FLASH_FAULT,
++ &req, sizeof(req), &resp, sizeof(resp));
++ if (!ret)
++ *fault = le32_to_cpu(resp.fault);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static const struct led_flash_ops gb_lights_flash_ops = {
++ .flash_brightness_set = gb_lights_flash_intensity_set,
++ .flash_brightness_get = gb_lights_flash_intensity_get,
++ .strobe_set = gb_lights_flash_strobe_set,
++ .strobe_get = gb_lights_flash_strobe_get,
++ .timeout_set = gb_lights_flash_timeout_set,
++ .fault_get = gb_lights_flash_fault_get,
++};
++
++static int __gb_lights_channel_torch_attach(struct gb_channel *channel,
++ struct gb_channel *channel_torch)
++{
++ char *name;
++
++ /* we can only attach torch to a flash channel */
++ if (!(channel->mode & GB_CHANNEL_MODE_FLASH))
++ return 0;
++
++ /* Move torch brightness to the destination */
++ channel->led->max_brightness = channel_torch->led->max_brightness;
++
++ /* append mode name to flash name */
++ name = kasprintf(GFP_KERNEL, "%s_%s", channel->led->name,
++ channel_torch->mode_name);
++ if (!name)
++ return -ENOMEM;
++ kfree(channel->led->name);
++ channel->led->name = name;
++
++ channel_torch->led = channel->led;
++
++ return 0;
++}
++
++static int __gb_lights_flash_led_register(struct gb_channel *channel)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct led_classdev_flash *fled = &channel->fled;
++ struct led_flash_setting *fset;
++ struct gb_channel *channel_torch;
++ int ret;
++
++ fled->ops = &gb_lights_flash_ops;
++
++ fled->led_cdev.flags |= LED_DEV_CAP_FLASH;
++
++ fset = &fled->brightness;
++ fset->min = channel->intensity_uA.min;
++ fset->max = channel->intensity_uA.max;
++ fset->step = channel->intensity_uA.step;
++ fset->val = channel->intensity_uA.max;
++
++ /* Only the flash mode have the timeout constraints settings */
++ if (channel->mode & GB_CHANNEL_MODE_FLASH) {
++ fset = &fled->timeout;
++ fset->min = channel->timeout_us.min;
++ fset->max = channel->timeout_us.max;
++ fset->step = channel->timeout_us.step;
++ fset->val = channel->timeout_us.max;
++ }
++
++ /*
++ * If light have torch mode channel, this channel will be the led
++ * classdev of the registered above flash classdev
++ */
++ channel_torch = get_channel_from_mode(channel->light,
++ GB_CHANNEL_MODE_TORCH);
++ if (channel_torch) {
++ ret = __gb_lights_channel_torch_attach(channel, channel_torch);
++ if (ret < 0)
++ goto fail;
++ }
++
++ ret = led_classdev_flash_register(&connection->bundle->dev, fled);
++ if (ret < 0)
++ goto fail;
++
++ channel->is_registered = true;
++ return 0;
++fail:
++ channel->led = NULL;
++ return ret;
++}
++
++static void __gb_lights_flash_led_unregister(struct gb_channel *channel)
++{
++ if (!channel->is_registered)
++ return;
++
++ led_classdev_flash_unregister(&channel->fled);
++}
++
++static int gb_lights_channel_flash_config(struct gb_channel *channel)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct gb_lights_get_channel_flash_config_request req;
++ struct gb_lights_get_channel_flash_config_response conf;
++ struct led_flash_setting *fset;
++ int ret;
++
++ req.light_id = channel->light->id;
++ req.channel_id = channel->id;
++
++ ret = gb_operation_sync(connection,
++ GB_LIGHTS_TYPE_GET_CHANNEL_FLASH_CONFIG,
++ &req, sizeof(req), &conf, sizeof(conf));
++ if (ret < 0)
++ return ret;
++
++ /*
++ * Intensity constraints for flash related modes: flash, torch,
++ * indicator. They will be needed for v4l2 registration.
++ */
++ fset = &channel->intensity_uA;
++ fset->min = le32_to_cpu(conf.intensity_min_uA);
++ fset->max = le32_to_cpu(conf.intensity_max_uA);
++ fset->step = le32_to_cpu(conf.intensity_step_uA);
++
++ /*
++ * On flash type, max brightness is set as the number of intensity steps
++ * available.
++ */
++ channel->led->max_brightness = (fset->max - fset->min) / fset->step;
++
++ /* Only the flash mode have the timeout constraints settings */
++ if (channel->mode & GB_CHANNEL_MODE_FLASH) {
++ fset = &channel->timeout_us;
++ fset->min = le32_to_cpu(conf.timeout_min_us);
++ fset->max = le32_to_cpu(conf.timeout_max_us);
++ fset->step = le32_to_cpu(conf.timeout_step_us);
++ }
++
++ return 0;
++}
++#else
++static int gb_lights_channel_flash_config(struct gb_channel *channel)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++
++ dev_err(&connection->bundle->dev, "no support for flash devices\n");
++ return 0;
++}
++
++static int __gb_lights_flash_led_register(struct gb_channel *channel)
++{
++ return 0;
++}
++
++static void __gb_lights_flash_led_unregister(struct gb_channel *channel)
++{
++}
++
++#endif
++
++static int __gb_lights_led_register(struct gb_channel *channel)
++{
++ struct gb_connection *connection = get_conn_from_channel(channel);
++ struct led_classdev *cdev = get_channel_cdev(channel);
++ int ret;
++
++ ret = led_classdev_register(&connection->bundle->dev, cdev);
++ if (ret < 0)
++ channel->led = NULL;
++ else
++ channel->is_registered = true;
++ return ret;
++}
++
++static int gb_lights_channel_register(struct gb_channel *channel)
++{
++ /* Normal LED channel, just register in led classdev and we are done */
++ if (!is_channel_flash(channel))
++ return __gb_lights_led_register(channel);
++
++ /*
++ * Flash Type need more work, register flash classdev, indicator as
++ * flash classdev, torch will be led classdev of the flash classdev.
++ */
++ if (!(channel->mode & GB_CHANNEL_MODE_TORCH))
++ return __gb_lights_flash_led_register(channel);
++
++ return 0;
++}
++
++static void __gb_lights_led_unregister(struct gb_channel *channel)
++{
++ struct led_classdev *cdev = get_channel_cdev(channel);
++
++ if (!channel->is_registered)
++ return;
++
++ led_classdev_unregister(cdev);
++ channel->led = NULL;
++}
++
++static void gb_lights_channel_unregister(struct gb_channel *channel)
++{
++ /* The same as register, handle channels differently */
++ if (!is_channel_flash(channel)) {
++ __gb_lights_led_unregister(channel);
++ return;
++ }
++
++ if (channel->mode & GB_CHANNEL_MODE_TORCH)
++ __gb_lights_led_unregister(channel);
++ else
++ __gb_lights_flash_led_unregister(channel);
++}
++
++static int gb_lights_channel_config(struct gb_light *light,
++ struct gb_channel *channel)
++{
++ struct gb_lights_get_channel_config_response conf;
++ struct gb_lights_get_channel_config_request req;
++ struct gb_connection *connection = get_conn_from_light(light);
++ struct led_classdev *cdev = get_channel_cdev(channel);
++ char *name;
++ int ret;
++
++ req.light_id = light->id;
++ req.channel_id = channel->id;
++
++ ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_CHANNEL_CONFIG,
++ &req, sizeof(req), &conf, sizeof(conf));
++ if (ret < 0)
++ return ret;
++
++ channel->light = light;
++ channel->mode = le32_to_cpu(conf.mode);
++ channel->flags = le32_to_cpu(conf.flags);
++ channel->color = le32_to_cpu(conf.color);
++ channel->color_name = kstrndup(conf.color_name, NAMES_MAX, GFP_KERNEL);
++ if (!channel->color_name)
++ return -ENOMEM;
++ channel->mode_name = kstrndup(conf.mode_name, NAMES_MAX, GFP_KERNEL);
++ if (!channel->mode_name)
++ return -ENOMEM;
++
++ channel->led = cdev;
++
++ name = kasprintf(GFP_KERNEL, "%s:%s:%s", light->name,
++ channel->color_name, channel->mode_name);
++ if (!name)
++ return -ENOMEM;
++
++ cdev->name = name;
++
++ cdev->max_brightness = conf.max_brightness;
++
++ ret = channel_attr_groups_set(channel, cdev);
++ if (ret < 0)
++ return ret;
++
++ gb_lights_led_operations_set(channel, cdev);
++
++ /*
++ * If it is not a flash related channel (flash, torch or indicator) we
++ * are done here. If not, continue and fetch flash related
++ * configurations.
++ */
++ if (!is_channel_flash(channel))
++ return ret;
++
++ light->has_flash = true;
++
++ ret = gb_lights_channel_flash_config(channel);
++ if (ret < 0)
++ return ret;
++
++ return ret;
++}
++
++static int gb_lights_light_config(struct gb_lights *glights, u8 id)
++{
++ struct gb_light *light = &glights->lights[id];
++ struct gb_lights_get_light_config_request req;
++ struct gb_lights_get_light_config_response conf;
++ int ret;
++ int i;
++
++ light->glights = glights;
++ light->id = id;
++
++ req.id = id;
++
++ ret = gb_operation_sync(glights->connection,
++ GB_LIGHTS_TYPE_GET_LIGHT_CONFIG,
++ &req, sizeof(req), &conf, sizeof(conf));
++ if (ret < 0)
++ return ret;
++
++ if (!conf.channel_count)
++ return -EINVAL;
++ if (!strlen(conf.name))
++ return -EINVAL;
++
++ light->channels_count = conf.channel_count;
++ light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL);
++
++ light->channels = kzalloc(light->channels_count *
++ sizeof(struct gb_channel), GFP_KERNEL);
++ if (!light->channels)
++ return -ENOMEM;
++
++ /* First we collect all the configurations for all channels */
++ for (i = 0; i < light->channels_count; i++) {
++ light->channels[i].id = i;
++ ret = gb_lights_channel_config(light, &light->channels[i]);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gb_lights_light_register(struct gb_light *light)
++{
++ int ret;
++ int i;
++
++ /*
++ * Then, if everything went ok in getting configurations, we register
++ * the classdev, flash classdev and v4l2 subsystem, if a flash device is
++ * found.
++ */
++ for (i = 0; i < light->channels_count; i++) {
++ ret = gb_lights_channel_register(&light->channels[i]);
++ if (ret < 0)
++ return ret;
++
++ mutex_init(&light->channels[i].lock);
++ }
++
++ light->ready = true;
++
++ if (light->has_flash) {
++ ret = gb_lights_light_v4l2_register(light);
++ if (ret < 0) {
++ light->has_flash = false;
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static void gb_lights_channel_free(struct gb_channel *channel)
++{
++ kfree(channel->attrs);
++ kfree(channel->attr_group);
++ kfree(channel->attr_groups);
++ kfree(channel->color_name);
++ kfree(channel->mode_name);
++ mutex_destroy(&channel->lock);
++}
++
++static void gb_lights_channel_release(struct gb_channel *channel)
++{
++ channel->releasing = true;
++
++ gb_lights_channel_unregister(channel);
++
++ gb_lights_channel_free(channel);
++}
++
++static void gb_lights_light_release(struct gb_light *light)
++{
++ int i;
++ int count;
++
++ light->ready = false;
++
++ count = light->channels_count;
++
++ if (light->has_flash)
++ gb_lights_light_v4l2_unregister(light);
++
++ for (i = 0; i < count; i++) {
++ gb_lights_channel_release(&light->channels[i]);
++ light->channels_count--;
++ }
++ kfree(light->channels);
++ kfree(light->name);
++}
++
++static void gb_lights_release(struct gb_lights *glights)
++{
++ int i;
++
++ if (!glights)
++ return;
++
++ mutex_lock(&glights->lights_lock);
++ if (!glights->lights)
++ goto free_glights;
++
++ for (i = 0; i < glights->lights_count; i++)
++ gb_lights_light_release(&glights->lights[i]);
++
++ kfree(glights->lights);
++
++free_glights:
++ mutex_unlock(&glights->lights_lock);
++ mutex_destroy(&glights->lights_lock);
++ kfree(glights);
++}
++
++static int gb_lights_get_count(struct gb_lights *glights)
++{
++ struct gb_lights_get_lights_response resp;
++ int ret;
++
++ ret = gb_operation_sync(glights->connection, GB_LIGHTS_TYPE_GET_LIGHTS,
++ NULL, 0, &resp, sizeof(resp));
++ if (ret < 0)
++ return ret;
++
++ if (!resp.lights_count)
++ return -EINVAL;
++
++ glights->lights_count = resp.lights_count;
++
++ return 0;
++}
++
++static int gb_lights_create_all(struct gb_lights *glights)
++{
++ struct gb_connection *connection = glights->connection;
++ int ret;
++ int i;
++
++ mutex_lock(&glights->lights_lock);
++ ret = gb_lights_get_count(glights);
++ if (ret < 0)
++ goto out;
++
++ glights->lights = kzalloc(glights->lights_count *
++ sizeof(struct gb_light), GFP_KERNEL);
++ if (!glights->lights) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ for (i = 0; i < glights->lights_count; i++) {
++ ret = gb_lights_light_config(glights, i);
++ if (ret < 0) {
++ dev_err(&connection->bundle->dev,
++ "Fail to configure lights device\n");
++ goto out;
++ }
++ }
++
++out:
++ mutex_unlock(&glights->lights_lock);
++ return ret;
++}
++
++static int gb_lights_register_all(struct gb_lights *glights)
++{
++ struct gb_connection *connection = glights->connection;
++ int ret = 0;
++ int i;
++
++ mutex_lock(&glights->lights_lock);
++ for (i = 0; i < glights->lights_count; i++) {
++ ret = gb_lights_light_register(&glights->lights[i]);
++ if (ret < 0) {
++ dev_err(&connection->bundle->dev,
++ "Fail to enable lights device\n");
++ break;
++ }
++ }
++
++ mutex_unlock(&glights->lights_lock);
++ return ret;
++}
++
++static int gb_lights_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct device *dev = &connection->bundle->dev;
++ struct gb_lights *glights = gb_connection_get_data(connection);
++ struct gb_light *light;
++ struct gb_message *request;
++ struct gb_lights_event_request *payload;
++ int ret = 0;
++ u8 light_id;
++ u8 event;
++
++ if (op->type != GB_LIGHTS_TYPE_EVENT) {
++ dev_err(dev, "Unsupported unsolicited event: %u\n", op->type);
++ return -EINVAL;
++ }
++
++ request = op->request;
++
++ if (request->payload_size < sizeof(*payload)) {
++ dev_err(dev, "Wrong event size received (%zu < %zu)\n",
++ request->payload_size, sizeof(*payload));
++ return -EINVAL;
++ }
++
++ payload = request->payload;
++ light_id = payload->light_id;
++
++ if (light_id >= glights->lights_count ||
++ !glights->lights[light_id].ready) {
++ dev_err(dev, "Event received for unconfigured light id: %d\n",
++ light_id);
++ return -EINVAL;
++ }
++
++ event = payload->event;
++
++ if (event & GB_LIGHTS_LIGHT_CONFIG) {
++ light = &glights->lights[light_id];
++
++ mutex_lock(&glights->lights_lock);
++ gb_lights_light_release(light);
++ ret = gb_lights_light_config(glights, light_id);
++ if (!ret)
++ ret = gb_lights_light_register(light);
++ if (ret < 0)
++ gb_lights_light_release(light);
++ mutex_unlock(&glights->lights_lock);
++ }
++
++ return ret;
++}
++
++static int gb_lights_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_lights *glights;
++ int ret;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LIGHTS)
++ return -ENODEV;
++
++ glights = kzalloc(sizeof(*glights), GFP_KERNEL);
++ if (!glights)
++ return -ENOMEM;
++
++ mutex_init(&glights->lights_lock);
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_lights_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto out;
++ }
++
++ glights->connection = connection;
++ gb_connection_set_data(connection, glights);
++
++ greybus_set_drvdata(bundle, glights);
++
++ /* We aren't ready to receive an incoming request yet */
++ ret = gb_connection_enable_tx(connection);
++ if (ret)
++ goto error_connection_destroy;
++
++ /*
++ * Setup all the lights devices over this connection, if anything goes
++ * wrong tear down all lights
++ */
++ ret = gb_lights_create_all(glights);
++ if (ret < 0)
++ goto error_connection_disable;
++
++ /* We are ready to receive an incoming request now, enable RX as well */
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto error_connection_disable;
++
++ /* Enable & register lights */
++ ret = gb_lights_register_all(glights);
++ if (ret < 0)
++ goto error_connection_disable;
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++error_connection_disable:
++ gb_connection_disable(connection);
++error_connection_destroy:
++ gb_connection_destroy(connection);
++out:
++ gb_lights_release(glights);
++ return ret;
++}
++
++static void gb_lights_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_lights *glights = greybus_get_drvdata(bundle);
++
++ if (gb_pm_runtime_get_sync(bundle))
++ gb_pm_runtime_get_noresume(bundle);
++
++ gb_connection_disable(glights->connection);
++ gb_connection_destroy(glights->connection);
++
++ gb_lights_release(glights);
++}
++
++static const struct greybus_bundle_id gb_lights_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_lights_id_table);
++
++static struct greybus_driver gb_lights_driver = {
++ .name = "lights",
++ .probe = gb_lights_probe,
++ .disconnect = gb_lights_disconnect,
++ .id_table = gb_lights_id_table,
++};
++module_greybus_driver(gb_lights_driver);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_log.patch b/greybus_log.patch
new file mode 100644
index 00000000000000..afde8529724f68
--- /dev/null
+++ b/greybus_log.patch
@@ -0,0 +1,139 @@
+---
+ drivers/greybus/log.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 132 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/log.c
+@@ -0,0 +1,132 @@
++/*
++ * Greybus driver for the log protocol
++ *
++ * Copyright 2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sizes.h>
++#include <linux/uaccess.h>
++
++#include "greybus.h"
++
++struct gb_log {
++ struct gb_connection *connection;
++};
++
++static int gb_log_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct device *dev = &connection->bundle->dev;
++ struct gb_log_send_log_request *receive;
++ u16 len;
++
++ if (op->type != GB_LOG_TYPE_SEND_LOG) {
++ dev_err(dev, "unknown request type 0x%02x\n", op->type);
++ return -EINVAL;
++ }
++
++ /* Verify size of payload */
++ if (op->request->payload_size < sizeof(*receive)) {
++ dev_err(dev, "log request too small (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*receive));
++ return -EINVAL;
++ }
++ receive = op->request->payload;
++ len = le16_to_cpu(receive->len);
++ if (len != (int)(op->request->payload_size - sizeof(*receive))) {
++ dev_err(dev, "log request wrong size %d vs %d\n", len,
++ (int)(op->request->payload_size - sizeof(*receive)));
++ return -EINVAL;
++ }
++ if (len == 0) {
++ dev_err(dev, "log request of 0 bytes?\n");
++ return -EINVAL;
++ }
++
++ if (len > GB_LOG_MAX_LEN) {
++ dev_err(dev, "log request too big: %d\n", len);
++ return -EINVAL;
++ }
++
++ /* Ensure the buffer is 0 terminated */
++ receive->msg[len - 1] = '\0';
++
++ /* Print with dev_dbg() so that it can be easily turned off using
++ * dynamic debugging (and prevent any DoS) */
++ dev_dbg(dev, "%s", receive->msg);
++
++ return 0;
++}
++
++static int gb_log_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_log *log;
++ int retval;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LOG)
++ return -ENODEV;
++
++ log = kzalloc(sizeof(*log), GFP_KERNEL);
++ if (!log)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_log_request_handler);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto error_free;
++ }
++
++ log->connection = connection;
++ greybus_set_drvdata(bundle, log);
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto error_connection_destroy;
++
++ return 0;
++
++error_connection_destroy:
++ gb_connection_destroy(connection);
++error_free:
++ kfree(log);
++ return retval;
++}
++
++static void gb_log_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_log *log = greybus_get_drvdata(bundle);
++ struct gb_connection *connection = log->connection;
++
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++
++ kfree(log);
++}
++
++static const struct greybus_bundle_id gb_log_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOG) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_log_id_table);
++
++static struct greybus_driver gb_log_driver = {
++ .name = "log",
++ .probe = gb_log_probe,
++ .disconnect = gb_log_disconnect,
++ .id_table = gb_log_id_table,
++};
++module_greybus_driver(gb_log_driver);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_loopback.patch b/greybus_loopback.patch
new file mode 100644
index 00000000000000..463a2052538bcb
--- /dev/null
+++ b/greybus_loopback.patch
@@ -0,0 +1,1372 @@
+---
+ drivers/greybus/loopback.c | 1365 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1365 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/loopback.c
+@@ -0,0 +1,1365 @@
++/*
++ * Loopback bridge driver for the Greybus loopback module.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/sizes.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/kfifo.h>
++#include <linux/debugfs.h>
++#include <linux/list_sort.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/atomic.h>
++#include <linux/pm_runtime.h>
++
++#include <asm/div64.h>
++
++#include "greybus.h"
++#include "connection.h"
++
++#define NSEC_PER_DAY 86400000000000ULL
++
++struct gb_loopback_stats {
++ u32 min;
++ u32 max;
++ u64 sum;
++ u32 count;
++};
++
++struct gb_loopback_device {
++ struct dentry *root;
++ u32 count;
++ size_t size_max;
++
++ /* We need to take a lock in atomic context */
++ spinlock_t lock;
++ struct list_head list;
++ struct list_head list_op_async;
++ wait_queue_head_t wq;
++};
++
++static struct gb_loopback_device gb_dev;
++
++struct gb_loopback_async_operation {
++ struct gb_loopback *gb;
++ struct gb_operation *operation;
++ struct timeval ts;
++ struct timer_list timer;
++ struct list_head entry;
++ struct work_struct work;
++ struct kref kref;
++ bool pending;
++ int (*completion)(struct gb_loopback_async_operation *op_async);
++};
++
++struct gb_loopback {
++ struct gb_connection *connection;
++
++ struct dentry *file;
++ struct kfifo kfifo_lat;
++ struct kfifo kfifo_ts;
++ struct mutex mutex;
++ struct task_struct *task;
++ struct list_head entry;
++ struct device *dev;
++ wait_queue_head_t wq;
++ wait_queue_head_t wq_completion;
++ atomic_t outstanding_operations;
++
++ /* Per connection stats */
++ struct timeval ts;
++ struct gb_loopback_stats latency;
++ struct gb_loopback_stats throughput;
++ struct gb_loopback_stats requests_per_second;
++ struct gb_loopback_stats apbridge_unipro_latency;
++ struct gb_loopback_stats gbphy_firmware_latency;
++
++ int type;
++ int async;
++ int id;
++ u32 size;
++ u32 iteration_max;
++ u32 iteration_count;
++ int us_wait;
++ u32 error;
++ u32 requests_completed;
++ u32 requests_timedout;
++ u32 timeout;
++ u32 jiffy_timeout;
++ u32 timeout_min;
++ u32 timeout_max;
++ u32 outstanding_operations_max;
++ u32 lbid;
++ u64 elapsed_nsecs;
++ u32 apbridge_latency_ts;
++ u32 gbphy_latency_ts;
++
++ u32 send_count;
++};
++
++static struct class loopback_class = {
++ .name = "gb_loopback",
++ .owner = THIS_MODULE,
++};
++static DEFINE_IDA(loopback_ida);
++
++/* Min/max values in jiffies */
++#define GB_LOOPBACK_TIMEOUT_MIN 1
++#define GB_LOOPBACK_TIMEOUT_MAX 10000
++
++#define GB_LOOPBACK_FIFO_DEFAULT 8192
++
++static unsigned kfifo_depth = GB_LOOPBACK_FIFO_DEFAULT;
++module_param(kfifo_depth, uint, 0444);
++
++/* Maximum size of any one send data buffer we support */
++#define MAX_PACKET_SIZE (PAGE_SIZE * 2)
++
++#define GB_LOOPBACK_US_WAIT_MAX 1000000
++
++/* interface sysfs attributes */
++#define gb_loopback_ro_attr(field) \
++static ssize_t field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ return sprintf(buf, "%u\n", gb->field); \
++} \
++static DEVICE_ATTR_RO(field)
++
++#define gb_loopback_ro_stats_attr(name, field, type) \
++static ssize_t name##_##field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ /* Report 0 for min and max if no transfer successed */ \
++ if (!gb->requests_completed) \
++ return sprintf(buf, "0\n"); \
++ return sprintf(buf, "%"#type"\n", gb->name.field); \
++} \
++static DEVICE_ATTR_RO(name##_##field)
++
++#define gb_loopback_ro_avg_attr(name) \
++static ssize_t name##_avg_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback_stats *stats; \
++ struct gb_loopback *gb; \
++ u64 avg, rem; \
++ u32 count; \
++ gb = dev_get_drvdata(dev); \
++ stats = &gb->name; \
++ count = stats->count ? stats->count : 1; \
++ avg = stats->sum + count / 2000000; /* round closest */ \
++ rem = do_div(avg, count); \
++ rem *= 1000000; \
++ do_div(rem, count); \
++ return sprintf(buf, "%llu.%06u\n", avg, (u32)rem); \
++} \
++static DEVICE_ATTR_RO(name##_avg)
++
++#define gb_loopback_stats_attrs(field) \
++ gb_loopback_ro_stats_attr(field, min, u); \
++ gb_loopback_ro_stats_attr(field, max, u); \
++ gb_loopback_ro_avg_attr(field)
++
++#define gb_loopback_attr(field, type) \
++static ssize_t field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ return sprintf(buf, "%"#type"\n", gb->field); \
++} \
++static ssize_t field##_store(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, \
++ size_t len) \
++{ \
++ int ret; \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ mutex_lock(&gb->mutex); \
++ ret = sscanf(buf, "%"#type, &gb->field); \
++ if (ret != 1) \
++ len = -EINVAL; \
++ else \
++ gb_loopback_check_attr(gb, bundle); \
++ mutex_unlock(&gb->mutex); \
++ return len; \
++} \
++static DEVICE_ATTR_RW(field)
++
++#define gb_dev_loopback_ro_attr(field, conn) \
++static ssize_t field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ return sprintf(buf, "%u\n", gb->field); \
++} \
++static DEVICE_ATTR_RO(field)
++
++#define gb_dev_loopback_rw_attr(field, type) \
++static ssize_t field##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ return sprintf(buf, "%"#type"\n", gb->field); \
++} \
++static ssize_t field##_store(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, \
++ size_t len) \
++{ \
++ int ret; \
++ struct gb_loopback *gb = dev_get_drvdata(dev); \
++ mutex_lock(&gb->mutex); \
++ ret = sscanf(buf, "%"#type, &gb->field); \
++ if (ret != 1) \
++ len = -EINVAL; \
++ else \
++ gb_loopback_check_attr(gb); \
++ mutex_unlock(&gb->mutex); \
++ return len; \
++} \
++static DEVICE_ATTR_RW(field)
++
++static void gb_loopback_reset_stats(struct gb_loopback *gb);
++static void gb_loopback_check_attr(struct gb_loopback *gb)
++{
++ if (gb->us_wait > GB_LOOPBACK_US_WAIT_MAX)
++ gb->us_wait = GB_LOOPBACK_US_WAIT_MAX;
++ if (gb->size > gb_dev.size_max)
++ gb->size = gb_dev.size_max;
++ gb->requests_timedout = 0;
++ gb->requests_completed = 0;
++ gb->iteration_count = 0;
++ gb->send_count = 0;
++ gb->error = 0;
++
++ if (kfifo_depth < gb->iteration_max) {
++ dev_warn(gb->dev,
++ "cannot log bytes %u kfifo_depth %u\n",
++ gb->iteration_max, kfifo_depth);
++ }
++ kfifo_reset_out(&gb->kfifo_lat);
++ kfifo_reset_out(&gb->kfifo_ts);
++
++ switch (gb->type) {
++ case GB_LOOPBACK_TYPE_PING:
++ case GB_LOOPBACK_TYPE_TRANSFER:
++ case GB_LOOPBACK_TYPE_SINK:
++ gb->jiffy_timeout = usecs_to_jiffies(gb->timeout);
++ if (!gb->jiffy_timeout)
++ gb->jiffy_timeout = GB_LOOPBACK_TIMEOUT_MIN;
++ else if (gb->jiffy_timeout > GB_LOOPBACK_TIMEOUT_MAX)
++ gb->jiffy_timeout = GB_LOOPBACK_TIMEOUT_MAX;
++ gb_loopback_reset_stats(gb);
++ wake_up(&gb->wq);
++ break;
++ default:
++ gb->type = 0;
++ break;
++ }
++}
++
++/* Time to send and receive one message */
++gb_loopback_stats_attrs(latency);
++/* Number of requests sent per second on this cport */
++gb_loopback_stats_attrs(requests_per_second);
++/* Quantity of data sent and received on this cport */
++gb_loopback_stats_attrs(throughput);
++/* Latency across the UniPro link from APBridge's perspective */
++gb_loopback_stats_attrs(apbridge_unipro_latency);
++/* Firmware induced overhead in the GPBridge */
++gb_loopback_stats_attrs(gbphy_firmware_latency);
++
++/* Number of errors encountered during loop */
++gb_loopback_ro_attr(error);
++/* Number of requests successfully completed async */
++gb_loopback_ro_attr(requests_completed);
++/* Number of requests timed out async */
++gb_loopback_ro_attr(requests_timedout);
++/* Timeout minimum in useconds */
++gb_loopback_ro_attr(timeout_min);
++/* Timeout minimum in useconds */
++gb_loopback_ro_attr(timeout_max);
++
++/*
++ * Type of loopback message to send based on protocol type definitions
++ * 0 => Don't send message
++ * 2 => Send ping message continuously (message without payload)
++ * 3 => Send transfer message continuously (message with payload,
++ * payload returned in response)
++ * 4 => Send a sink message (message with payload, no payload in response)
++ */
++gb_dev_loopback_rw_attr(type, d);
++/* Size of transfer message payload: 0-4096 bytes */
++gb_dev_loopback_rw_attr(size, u);
++/* Time to wait between two messages: 0-1000 ms */
++gb_dev_loopback_rw_attr(us_wait, d);
++/* Maximum iterations for a given operation: 1-(2^32-1), 0 implies infinite */
++gb_dev_loopback_rw_attr(iteration_max, u);
++/* The current index of the for (i = 0; i < iteration_max; i++) loop */
++gb_dev_loopback_ro_attr(iteration_count, false);
++/* A flag to indicate synchronous or asynchronous operations */
++gb_dev_loopback_rw_attr(async, u);
++/* Timeout of an individual asynchronous request */
++gb_dev_loopback_rw_attr(timeout, u);
++/* Maximum number of in-flight operations before back-off */
++gb_dev_loopback_rw_attr(outstanding_operations_max, u);
++
++static struct attribute *loopback_attrs[] = {
++ &dev_attr_latency_min.attr,
++ &dev_attr_latency_max.attr,
++ &dev_attr_latency_avg.attr,
++ &dev_attr_requests_per_second_min.attr,
++ &dev_attr_requests_per_second_max.attr,
++ &dev_attr_requests_per_second_avg.attr,
++ &dev_attr_throughput_min.attr,
++ &dev_attr_throughput_max.attr,
++ &dev_attr_throughput_avg.attr,
++ &dev_attr_apbridge_unipro_latency_min.attr,
++ &dev_attr_apbridge_unipro_latency_max.attr,
++ &dev_attr_apbridge_unipro_latency_avg.attr,
++ &dev_attr_gbphy_firmware_latency_min.attr,
++ &dev_attr_gbphy_firmware_latency_max.attr,
++ &dev_attr_gbphy_firmware_latency_avg.attr,
++ &dev_attr_type.attr,
++ &dev_attr_size.attr,
++ &dev_attr_us_wait.attr,
++ &dev_attr_iteration_count.attr,
++ &dev_attr_iteration_max.attr,
++ &dev_attr_async.attr,
++ &dev_attr_error.attr,
++ &dev_attr_requests_completed.attr,
++ &dev_attr_requests_timedout.attr,
++ &dev_attr_timeout.attr,
++ &dev_attr_outstanding_operations_max.attr,
++ &dev_attr_timeout_min.attr,
++ &dev_attr_timeout_max.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(loopback);
++
++static void gb_loopback_calculate_stats(struct gb_loopback *gb, bool error);
++
++static u32 gb_loopback_nsec_to_usec_latency(u64 elapsed_nsecs)
++{
++ u32 lat;
++
++ do_div(elapsed_nsecs, NSEC_PER_USEC);
++ lat = elapsed_nsecs;
++ return lat;
++}
++
++static u64 __gb_loopback_calc_latency(u64 t1, u64 t2)
++{
++ if (t2 > t1)
++ return t2 - t1;
++ else
++ return NSEC_PER_DAY - t2 + t1;
++}
++
++static u64 gb_loopback_calc_latency(struct timeval *ts, struct timeval *te)
++{
++ u64 t1, t2;
++
++ t1 = timeval_to_ns(ts);
++ t2 = timeval_to_ns(te);
++
++ return __gb_loopback_calc_latency(t1, t2);
++}
++
++static void gb_loopback_push_latency_ts(struct gb_loopback *gb,
++ struct timeval *ts, struct timeval *te)
++{
++ kfifo_in(&gb->kfifo_ts, (unsigned char *)ts, sizeof(*ts));
++ kfifo_in(&gb->kfifo_ts, (unsigned char *)te, sizeof(*te));
++}
++
++static int gb_loopback_operation_sync(struct gb_loopback *gb, int type,
++ void *request, int request_size,
++ void *response, int response_size)
++{
++ struct gb_operation *operation;
++ struct timeval ts, te;
++ int ret;
++
++ do_gettimeofday(&ts);
++ operation = gb_operation_create(gb->connection, type, request_size,
++ response_size, GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ if (request_size)
++ memcpy(operation->request->payload, request, request_size);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret) {
++ dev_err(&gb->connection->bundle->dev,
++ "synchronous operation failed: %d\n", ret);
++ goto out_put_operation;
++ } else {
++ if (response_size == operation->response->payload_size) {
++ memcpy(response, operation->response->payload,
++ response_size);
++ } else {
++ dev_err(&gb->connection->bundle->dev,
++ "response size %zu expected %d\n",
++ operation->response->payload_size,
++ response_size);
++ ret = -EINVAL;
++ goto out_put_operation;
++ }
++ }
++
++ do_gettimeofday(&te);
++
++ /* Calculate the total time the message took */
++ gb_loopback_push_latency_ts(gb, &ts, &te);
++ gb->elapsed_nsecs = gb_loopback_calc_latency(&ts, &te);
++
++out_put_operation:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static void __gb_loopback_async_operation_destroy(struct kref *kref)
++{
++ struct gb_loopback_async_operation *op_async;
++
++ op_async = container_of(kref, struct gb_loopback_async_operation, kref);
++
++ list_del(&op_async->entry);
++ if (op_async->operation)
++ gb_operation_put(op_async->operation);
++ atomic_dec(&op_async->gb->outstanding_operations);
++ wake_up(&op_async->gb->wq_completion);
++ kfree(op_async);
++}
++
++static void gb_loopback_async_operation_get(struct gb_loopback_async_operation
++ *op_async)
++{
++ kref_get(&op_async->kref);
++}
++
++static void gb_loopback_async_operation_put(struct gb_loopback_async_operation
++ *op_async)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&gb_dev.lock, flags);
++ kref_put(&op_async->kref, __gb_loopback_async_operation_destroy);
++ spin_unlock_irqrestore(&gb_dev.lock, flags);
++}
++
++static struct gb_loopback_async_operation *
++ gb_loopback_operation_find(u16 id)
++{
++ struct gb_loopback_async_operation *op_async;
++ bool found = false;
++ unsigned long flags;
++
++ spin_lock_irqsave(&gb_dev.lock, flags);
++ list_for_each_entry(op_async, &gb_dev.list_op_async, entry) {
++ if (op_async->operation->id == id) {
++ gb_loopback_async_operation_get(op_async);
++ found = true;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&gb_dev.lock, flags);
++
++ return found ? op_async : NULL;
++}
++
++static void gb_loopback_async_wait_all(struct gb_loopback *gb)
++{
++ wait_event(gb->wq_completion,
++ !atomic_read(&gb->outstanding_operations));
++}
++
++static void gb_loopback_async_operation_callback(struct gb_operation *operation)
++{
++ struct gb_loopback_async_operation *op_async;
++ struct gb_loopback *gb;
++ struct timeval te;
++ bool err = false;
++
++ do_gettimeofday(&te);
++ op_async = gb_loopback_operation_find(operation->id);
++ if (!op_async)
++ return;
++
++ gb = op_async->gb;
++ mutex_lock(&gb->mutex);
++
++ if (!op_async->pending || gb_operation_result(operation)) {
++ err = true;
++ } else {
++ if (op_async->completion)
++ if (op_async->completion(op_async))
++ err = true;
++ }
++
++ if (!err) {
++ gb_loopback_push_latency_ts(gb, &op_async->ts, &te);
++ gb->elapsed_nsecs = gb_loopback_calc_latency(&op_async->ts,
++ &te);
++ }
++
++ if (op_async->pending) {
++ if (err)
++ gb->error++;
++ gb->iteration_count++;
++ op_async->pending = false;
++ del_timer_sync(&op_async->timer);
++ gb_loopback_async_operation_put(op_async);
++ gb_loopback_calculate_stats(gb, err);
++ }
++ mutex_unlock(&gb->mutex);
++
++ dev_dbg(&gb->connection->bundle->dev, "complete operation %d\n",
++ operation->id);
++
++ gb_loopback_async_operation_put(op_async);
++}
++
++static void gb_loopback_async_operation_work(struct work_struct *work)
++{
++ struct gb_loopback *gb;
++ struct gb_operation *operation;
++ struct gb_loopback_async_operation *op_async;
++
++ op_async = container_of(work, struct gb_loopback_async_operation, work);
++ gb = op_async->gb;
++ operation = op_async->operation;
++
++ mutex_lock(&gb->mutex);
++ if (op_async->pending) {
++ gb->requests_timedout++;
++ gb->error++;
++ gb->iteration_count++;
++ op_async->pending = false;
++ gb_loopback_async_operation_put(op_async);
++ gb_loopback_calculate_stats(gb, true);
++ }
++ mutex_unlock(&gb->mutex);
++
++ dev_dbg(&gb->connection->bundle->dev, "timeout operation %d\n",
++ operation->id);
++
++ gb_operation_cancel(operation, -ETIMEDOUT);
++ gb_loopback_async_operation_put(op_async);
++}
++
++static void gb_loopback_async_operation_timeout(unsigned long data)
++{
++ struct gb_loopback_async_operation *op_async;
++ u16 id = data;
++
++ op_async = gb_loopback_operation_find(id);
++ if (!op_async) {
++ pr_err("operation %d not found - time out ?\n", id);
++ return;
++ }
++ schedule_work(&op_async->work);
++}
++
++static int gb_loopback_async_operation(struct gb_loopback *gb, int type,
++ void *request, int request_size,
++ int response_size,
++ void *completion)
++{
++ struct gb_loopback_async_operation *op_async;
++ struct gb_operation *operation;
++ int ret;
++ unsigned long flags;
++
++ op_async = kzalloc(sizeof(*op_async), GFP_KERNEL);
++ if (!op_async)
++ return -ENOMEM;
++
++ INIT_WORK(&op_async->work, gb_loopback_async_operation_work);
++ init_timer(&op_async->timer);
++ kref_init(&op_async->kref);
++
++ operation = gb_operation_create(gb->connection, type, request_size,
++ response_size, GFP_KERNEL);
++ if (!operation) {
++ kfree(op_async);
++ return -ENOMEM;
++ }
++
++ if (request_size)
++ memcpy(operation->request->payload, request, request_size);
++
++ op_async->gb = gb;
++ op_async->operation = operation;
++ op_async->completion = completion;
++
++ spin_lock_irqsave(&gb_dev.lock, flags);
++ list_add_tail(&op_async->entry, &gb_dev.list_op_async);
++ spin_unlock_irqrestore(&gb_dev.lock, flags);
++
++ do_gettimeofday(&op_async->ts);
++ op_async->pending = true;
++ atomic_inc(&gb->outstanding_operations);
++ mutex_lock(&gb->mutex);
++ ret = gb_operation_request_send(operation,
++ gb_loopback_async_operation_callback,
++ GFP_KERNEL);
++ if (ret)
++ goto error;
++
++ op_async->timer.function = gb_loopback_async_operation_timeout;
++ op_async->timer.expires = jiffies + gb->jiffy_timeout;
++ op_async->timer.data = (unsigned long)operation->id;
++ add_timer(&op_async->timer);
++
++ goto done;
++error:
++ gb_loopback_async_operation_put(op_async);
++done:
++ mutex_unlock(&gb->mutex);
++ return ret;
++}
++
++static int gb_loopback_sync_sink(struct gb_loopback *gb, u32 len)
++{
++ struct gb_loopback_transfer_request *request;
++ int retval;
++
++ request = kmalloc(len + sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ request->len = cpu_to_le32(len);
++ retval = gb_loopback_operation_sync(gb, GB_LOOPBACK_TYPE_SINK,
++ request, len + sizeof(*request),
++ NULL, 0);
++ kfree(request);
++ return retval;
++}
++
++static int gb_loopback_sync_transfer(struct gb_loopback *gb, u32 len)
++{
++ struct gb_loopback_transfer_request *request;
++ struct gb_loopback_transfer_response *response;
++ int retval;
++
++ gb->apbridge_latency_ts = 0;
++ gb->gbphy_latency_ts = 0;
++
++ request = kmalloc(len + sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++ response = kmalloc(len + sizeof(*response), GFP_KERNEL);
++ if (!response) {
++ kfree(request);
++ return -ENOMEM;
++ }
++
++ memset(request->data, 0x5A, len);
++
++ request->len = cpu_to_le32(len);
++ retval = gb_loopback_operation_sync(gb, GB_LOOPBACK_TYPE_TRANSFER,
++ request, len + sizeof(*request),
++ response, len + sizeof(*response));
++ if (retval)
++ goto gb_error;
++
++ if (memcmp(request->data, response->data, len)) {
++ dev_err(&gb->connection->bundle->dev,
++ "Loopback Data doesn't match\n");
++ retval = -EREMOTEIO;
++ }
++ gb->apbridge_latency_ts = (u32)__le32_to_cpu(response->reserved0);
++ gb->gbphy_latency_ts = (u32)__le32_to_cpu(response->reserved1);
++
++gb_error:
++ kfree(request);
++ kfree(response);
++
++ return retval;
++}
++
++static int gb_loopback_sync_ping(struct gb_loopback *gb)
++{
++ return gb_loopback_operation_sync(gb, GB_LOOPBACK_TYPE_PING,
++ NULL, 0, NULL, 0);
++}
++
++static int gb_loopback_async_sink(struct gb_loopback *gb, u32 len)
++{
++ struct gb_loopback_transfer_request *request;
++ int retval;
++
++ request = kmalloc(len + sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ request->len = cpu_to_le32(len);
++ retval = gb_loopback_async_operation(gb, GB_LOOPBACK_TYPE_SINK,
++ request, len + sizeof(*request),
++ 0, NULL);
++ kfree(request);
++ return retval;
++}
++
++static int gb_loopback_async_transfer_complete(
++ struct gb_loopback_async_operation *op_async)
++{
++ struct gb_loopback *gb;
++ struct gb_operation *operation;
++ struct gb_loopback_transfer_request *request;
++ struct gb_loopback_transfer_response *response;
++ size_t len;
++ int retval = 0;
++
++ gb = op_async->gb;
++ operation = op_async->operation;
++ request = operation->request->payload;
++ response = operation->response->payload;
++ len = le32_to_cpu(request->len);
++
++ if (memcmp(request->data, response->data, len)) {
++ dev_err(&gb->connection->bundle->dev,
++ "Loopback Data doesn't match operation id %d\n",
++ operation->id);
++ retval = -EREMOTEIO;
++ } else {
++ gb->apbridge_latency_ts =
++ (u32)__le32_to_cpu(response->reserved0);
++ gb->gbphy_latency_ts =
++ (u32)__le32_to_cpu(response->reserved1);
++ }
++
++ return retval;
++}
++
++static int gb_loopback_async_transfer(struct gb_loopback *gb, u32 len)
++{
++ struct gb_loopback_transfer_request *request;
++ int retval, response_len;
++
++ request = kmalloc(len + sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ memset(request->data, 0x5A, len);
++
++ request->len = cpu_to_le32(len);
++ response_len = sizeof(struct gb_loopback_transfer_response);
++ retval = gb_loopback_async_operation(gb, GB_LOOPBACK_TYPE_TRANSFER,
++ request, len + sizeof(*request),
++ len + response_len,
++ gb_loopback_async_transfer_complete);
++ if (retval)
++ goto gb_error;
++
++gb_error:
++ kfree(request);
++ return retval;
++}
++
++static int gb_loopback_async_ping(struct gb_loopback *gb)
++{
++ return gb_loopback_async_operation(gb, GB_LOOPBACK_TYPE_PING,
++ NULL, 0, 0, NULL);
++}
++
++static int gb_loopback_request_handler(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ struct gb_loopback_transfer_request *request;
++ struct gb_loopback_transfer_response *response;
++ struct device *dev = &connection->bundle->dev;
++ size_t len;
++
++ /* By convention, the AP initiates the version operation */
++ switch (operation->type) {
++ case GB_LOOPBACK_TYPE_PING:
++ case GB_LOOPBACK_TYPE_SINK:
++ return 0;
++ case GB_LOOPBACK_TYPE_TRANSFER:
++ if (operation->request->payload_size < sizeof(*request)) {
++ dev_err(dev, "transfer request too small (%zu < %zu)\n",
++ operation->request->payload_size,
++ sizeof(*request));
++ return -EINVAL; /* -EMSGSIZE */
++ }
++ request = operation->request->payload;
++ len = le32_to_cpu(request->len);
++ if (len > gb_dev.size_max) {
++ dev_err(dev, "transfer request too large (%zu > %zu)\n",
++ len, gb_dev.size_max);
++ return -EINVAL;
++ }
++
++ if (!gb_operation_response_alloc(operation,
++ len + sizeof(*response), GFP_KERNEL)) {
++ dev_err(dev, "error allocating response\n");
++ return -ENOMEM;
++ }
++ response = operation->response->payload;
++ response->len = cpu_to_le32(len);
++ if (len)
++ memcpy(response->data, request->data, len);
++
++ return 0;
++ default:
++ dev_err(dev, "unsupported request: %u\n", operation->type);
++ return -EINVAL;
++ }
++}
++
++static void gb_loopback_reset_stats(struct gb_loopback *gb)
++{
++ struct gb_loopback_stats reset = {
++ .min = U32_MAX,
++ };
++
++ /* Reset per-connection stats */
++ memcpy(&gb->latency, &reset,
++ sizeof(struct gb_loopback_stats));
++ memcpy(&gb->throughput, &reset,
++ sizeof(struct gb_loopback_stats));
++ memcpy(&gb->requests_per_second, &reset,
++ sizeof(struct gb_loopback_stats));
++ memcpy(&gb->apbridge_unipro_latency, &reset,
++ sizeof(struct gb_loopback_stats));
++ memcpy(&gb->gbphy_firmware_latency, &reset,
++ sizeof(struct gb_loopback_stats));
++
++ /* Should be initialized at least once per transaction set */
++ gb->apbridge_latency_ts = 0;
++ gb->gbphy_latency_ts = 0;
++ memset(&gb->ts, 0, sizeof(struct timeval));
++}
++
++static void gb_loopback_update_stats(struct gb_loopback_stats *stats, u32 val)
++{
++ if (stats->min > val)
++ stats->min = val;
++ if (stats->max < val)
++ stats->max = val;
++ stats->sum += val;
++ stats->count++;
++}
++
++static void gb_loopback_update_stats_window(struct gb_loopback_stats *stats,
++ u64 val, u32 count)
++{
++ stats->sum += val;
++ stats->count += count;
++
++ do_div(val, count);
++ if (stats->min > val)
++ stats->min = val;
++ if (stats->max < val)
++ stats->max = val;
++}
++
++static void gb_loopback_requests_update(struct gb_loopback *gb, u32 latency)
++{
++ u64 req = gb->requests_completed * USEC_PER_SEC;
++
++ gb_loopback_update_stats_window(&gb->requests_per_second, req, latency);
++}
++
++static void gb_loopback_throughput_update(struct gb_loopback *gb, u32 latency)
++{
++ u64 aggregate_size = sizeof(struct gb_operation_msg_hdr) * 2;
++
++ switch (gb->type) {
++ case GB_LOOPBACK_TYPE_PING:
++ break;
++ case GB_LOOPBACK_TYPE_SINK:
++ aggregate_size += sizeof(struct gb_loopback_transfer_request) +
++ gb->size;
++ break;
++ case GB_LOOPBACK_TYPE_TRANSFER:
++ aggregate_size += sizeof(struct gb_loopback_transfer_request) +
++ sizeof(struct gb_loopback_transfer_response) +
++ gb->size * 2;
++ break;
++ default:
++ return;
++ }
++
++ aggregate_size *= gb->requests_completed;
++ aggregate_size *= USEC_PER_SEC;
++ gb_loopback_update_stats_window(&gb->throughput, aggregate_size,
++ latency);
++}
++
++static void gb_loopback_calculate_latency_stats(struct gb_loopback *gb)
++{
++ u32 lat;
++
++ /* Express latency in terms of microseconds */
++ lat = gb_loopback_nsec_to_usec_latency(gb->elapsed_nsecs);
++
++ /* Log latency stastic */
++ gb_loopback_update_stats(&gb->latency, lat);
++
++ /* Raw latency log on a per thread basis */
++ kfifo_in(&gb->kfifo_lat, (unsigned char *)&lat, sizeof(lat));
++
++ /* Log the firmware supplied latency values */
++ gb_loopback_update_stats(&gb->apbridge_unipro_latency,
++ gb->apbridge_latency_ts);
++ gb_loopback_update_stats(&gb->gbphy_firmware_latency,
++ gb->gbphy_latency_ts);
++}
++
++static void gb_loopback_calculate_stats(struct gb_loopback *gb, bool error)
++{
++ u64 nlat;
++ u32 lat;
++ struct timeval te;
++
++ if (!error) {
++ gb->requests_completed++;
++ gb_loopback_calculate_latency_stats(gb);
++ }
++
++ do_gettimeofday(&te);
++ nlat = gb_loopback_calc_latency(&gb->ts, &te);
++ if (nlat >= NSEC_PER_SEC || gb->iteration_count == gb->iteration_max) {
++ lat = gb_loopback_nsec_to_usec_latency(nlat);
++
++ gb_loopback_throughput_update(gb, lat);
++ gb_loopback_requests_update(gb, lat);
++
++ if (gb->iteration_count != gb->iteration_max) {
++ gb->ts = te;
++ gb->requests_completed = 0;
++ }
++ }
++}
++
++static void gb_loopback_async_wait_to_send(struct gb_loopback *gb)
++{
++ if (!(gb->async && gb->outstanding_operations_max))
++ return;
++ wait_event_interruptible(gb->wq_completion,
++ (atomic_read(&gb->outstanding_operations) <
++ gb->outstanding_operations_max) ||
++ kthread_should_stop());
++}
++
++static int gb_loopback_fn(void *data)
++{
++ int error = 0;
++ int us_wait = 0;
++ int type;
++ int ret;
++ u32 size;
++
++ struct gb_loopback *gb = data;
++ struct gb_bundle *bundle = gb->connection->bundle;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ while (1) {
++ if (!gb->type) {
++ gb_pm_runtime_put_autosuspend(bundle);
++ wait_event_interruptible(gb->wq, gb->type ||
++ kthread_should_stop());
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++ }
++
++ if (kthread_should_stop())
++ break;
++
++ /* Limit the maximum number of in-flight async operations */
++ gb_loopback_async_wait_to_send(gb);
++ if (kthread_should_stop())
++ break;
++
++ mutex_lock(&gb->mutex);
++
++ /* Optionally terminate */
++ if (gb->send_count == gb->iteration_max) {
++ if (gb->iteration_count == gb->iteration_max) {
++ gb->type = 0;
++ gb->send_count = 0;
++ sysfs_notify(&gb->dev->kobj, NULL,
++ "iteration_count");
++ }
++ mutex_unlock(&gb->mutex);
++ continue;
++ }
++ size = gb->size;
++ us_wait = gb->us_wait;
++ type = gb->type;
++ if (gb->ts.tv_usec == 0 && gb->ts.tv_sec == 0)
++ do_gettimeofday(&gb->ts);
++ mutex_unlock(&gb->mutex);
++
++ /* Else operations to perform */
++ if (gb->async) {
++ if (type == GB_LOOPBACK_TYPE_PING) {
++ error = gb_loopback_async_ping(gb);
++ } else if (type == GB_LOOPBACK_TYPE_TRANSFER) {
++ error = gb_loopback_async_transfer(gb, size);
++ } else if (type == GB_LOOPBACK_TYPE_SINK) {
++ error = gb_loopback_async_sink(gb, size);
++ }
++
++ if (error)
++ gb->error++;
++ } else {
++ /* We are effectively single threaded here */
++ if (type == GB_LOOPBACK_TYPE_PING)
++ error = gb_loopback_sync_ping(gb);
++ else if (type == GB_LOOPBACK_TYPE_TRANSFER)
++ error = gb_loopback_sync_transfer(gb, size);
++ else if (type == GB_LOOPBACK_TYPE_SINK)
++ error = gb_loopback_sync_sink(gb, size);
++
++ if (error)
++ gb->error++;
++ gb->iteration_count++;
++ gb_loopback_calculate_stats(gb, !!error);
++ }
++ gb->send_count++;
++ if (us_wait)
++ udelay(us_wait);
++ }
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++}
++
++static int gb_loopback_dbgfs_latency_show_common(struct seq_file *s,
++ struct kfifo *kfifo,
++ struct mutex *mutex)
++{
++ u32 latency;
++ int retval;
++
++ if (kfifo_len(kfifo) == 0) {
++ retval = -EAGAIN;
++ goto done;
++ }
++
++ mutex_lock(mutex);
++ retval = kfifo_out(kfifo, &latency, sizeof(latency));
++ if (retval > 0) {
++ seq_printf(s, "%u", latency);
++ retval = 0;
++ }
++ mutex_unlock(mutex);
++done:
++ return retval;
++}
++
++static int gb_loopback_dbgfs_latency_show(struct seq_file *s, void *unused)
++{
++ struct gb_loopback *gb = s->private;
++
++ return gb_loopback_dbgfs_latency_show_common(s, &gb->kfifo_lat,
++ &gb->mutex);
++}
++
++static int gb_loopback_latency_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, gb_loopback_dbgfs_latency_show,
++ inode->i_private);
++}
++
++static const struct file_operations gb_loopback_debugfs_latency_ops = {
++ .open = gb_loopback_latency_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int gb_loopback_bus_id_compare(void *priv, struct list_head *lha,
++ struct list_head *lhb)
++{
++ struct gb_loopback *a = list_entry(lha, struct gb_loopback, entry);
++ struct gb_loopback *b = list_entry(lhb, struct gb_loopback, entry);
++ struct gb_connection *ca = a->connection;
++ struct gb_connection *cb = b->connection;
++
++ if (ca->bundle->intf->interface_id < cb->bundle->intf->interface_id)
++ return -1;
++ if (cb->bundle->intf->interface_id < ca->bundle->intf->interface_id)
++ return 1;
++ if (ca->bundle->id < cb->bundle->id)
++ return -1;
++ if (cb->bundle->id < ca->bundle->id)
++ return 1;
++ if (ca->intf_cport_id < cb->intf_cport_id)
++ return -1;
++ else if (cb->intf_cport_id < ca->intf_cport_id)
++ return 1;
++
++ return 0;
++}
++
++static void gb_loopback_insert_id(struct gb_loopback *gb)
++{
++ struct gb_loopback *gb_list;
++ u32 new_lbid = 0;
++
++ /* perform an insertion sort */
++ list_add_tail(&gb->entry, &gb_dev.list);
++ list_sort(NULL, &gb_dev.list, gb_loopback_bus_id_compare);
++ list_for_each_entry(gb_list, &gb_dev.list, entry) {
++ gb_list->lbid = 1 << new_lbid;
++ new_lbid++;
++ }
++}
++
++#define DEBUGFS_NAMELEN 32
++
++static int gb_loopback_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_loopback *gb;
++ struct device *dev;
++ int retval;
++ char name[DEBUGFS_NAMELEN];
++ unsigned long flags;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LOOPBACK)
++ return -ENODEV;
++
++ gb = kzalloc(sizeof(*gb), GFP_KERNEL);
++ if (!gb)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_loopback_request_handler);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto out_kzalloc;
++ }
++
++ gb->connection = connection;
++ greybus_set_drvdata(bundle, gb);
++
++ init_waitqueue_head(&gb->wq);
++ init_waitqueue_head(&gb->wq_completion);
++ atomic_set(&gb->outstanding_operations, 0);
++ gb_loopback_reset_stats(gb);
++
++ /* Reported values to user-space for min/max timeouts */
++ gb->timeout_min = jiffies_to_usecs(GB_LOOPBACK_TIMEOUT_MIN);
++ gb->timeout_max = jiffies_to_usecs(GB_LOOPBACK_TIMEOUT_MAX);
++
++ if (!gb_dev.count) {
++ /* Calculate maximum payload */
++ gb_dev.size_max = gb_operation_get_payload_size_max(connection);
++ if (gb_dev.size_max <=
++ sizeof(struct gb_loopback_transfer_request)) {
++ retval = -EINVAL;
++ goto out_connection_destroy;
++ }
++ gb_dev.size_max -= sizeof(struct gb_loopback_transfer_request);
++ }
++
++ /* Create per-connection sysfs and debugfs data-points */
++ snprintf(name, sizeof(name), "raw_latency_%s",
++ dev_name(&connection->bundle->dev));
++ gb->file = debugfs_create_file(name, S_IFREG | S_IRUGO, gb_dev.root, gb,
++ &gb_loopback_debugfs_latency_ops);
++
++ gb->id = ida_simple_get(&loopback_ida, 0, 0, GFP_KERNEL);
++ if (gb->id < 0) {
++ retval = gb->id;
++ goto out_debugfs_remove;
++ }
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto out_ida_remove;
++
++ dev = device_create_with_groups(&loopback_class,
++ &connection->bundle->dev,
++ MKDEV(0, 0), gb, loopback_groups,
++ "gb_loopback%d", gb->id);
++ if (IS_ERR(dev)) {
++ retval = PTR_ERR(dev);
++ goto out_connection_disable;
++ }
++ gb->dev = dev;
++
++ /* Allocate kfifo */
++ if (kfifo_alloc(&gb->kfifo_lat, kfifo_depth * sizeof(u32),
++ GFP_KERNEL)) {
++ retval = -ENOMEM;
++ goto out_conn;
++ }
++ if (kfifo_alloc(&gb->kfifo_ts, kfifo_depth * sizeof(struct timeval) * 2,
++ GFP_KERNEL)) {
++ retval = -ENOMEM;
++ goto out_kfifo0;
++ }
++
++ /* Fork worker thread */
++ mutex_init(&gb->mutex);
++ gb->task = kthread_run(gb_loopback_fn, gb, "gb_loopback");
++ if (IS_ERR(gb->task)) {
++ retval = PTR_ERR(gb->task);
++ goto out_kfifo1;
++ }
++
++ spin_lock_irqsave(&gb_dev.lock, flags);
++ gb_loopback_insert_id(gb);
++ gb_dev.count++;
++ spin_unlock_irqrestore(&gb_dev.lock, flags);
++
++ gb_connection_latency_tag_enable(connection);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++out_kfifo1:
++ kfifo_free(&gb->kfifo_ts);
++out_kfifo0:
++ kfifo_free(&gb->kfifo_lat);
++out_conn:
++ device_unregister(dev);
++out_connection_disable:
++ gb_connection_disable(connection);
++out_ida_remove:
++ ida_simple_remove(&loopback_ida, gb->id);
++out_debugfs_remove:
++ debugfs_remove(gb->file);
++out_connection_destroy:
++ gb_connection_destroy(connection);
++out_kzalloc:
++ kfree(gb);
++
++ return retval;
++}
++
++static void gb_loopback_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_loopback *gb = greybus_get_drvdata(bundle);
++ unsigned long flags;
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ gb_pm_runtime_get_noresume(bundle);
++
++ gb_connection_disable(gb->connection);
++
++ if (!IS_ERR_OR_NULL(gb->task))
++ kthread_stop(gb->task);
++
++ kfifo_free(&gb->kfifo_lat);
++ kfifo_free(&gb->kfifo_ts);
++ gb_connection_latency_tag_disable(gb->connection);
++ debugfs_remove(gb->file);
++
++ /*
++ * FIXME: gb_loopback_async_wait_all() is redundant now, as connection
++ * is disabled at the beginning and so we can't have any more
++ * incoming/outgoing requests.
++ */
++ gb_loopback_async_wait_all(gb);
++
++ spin_lock_irqsave(&gb_dev.lock, flags);
++ gb_dev.count--;
++ list_del(&gb->entry);
++ spin_unlock_irqrestore(&gb_dev.lock, flags);
++
++ device_unregister(gb->dev);
++ ida_simple_remove(&loopback_ida, gb->id);
++
++ gb_connection_destroy(gb->connection);
++ kfree(gb);
++}
++
++static const struct greybus_bundle_id gb_loopback_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOOPBACK) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_loopback_id_table);
++
++static struct greybus_driver gb_loopback_driver = {
++ .name = "loopback",
++ .probe = gb_loopback_probe,
++ .disconnect = gb_loopback_disconnect,
++ .id_table = gb_loopback_id_table,
++};
++
++static int loopback_init(void)
++{
++ int retval;
++
++ INIT_LIST_HEAD(&gb_dev.list);
++ INIT_LIST_HEAD(&gb_dev.list_op_async);
++ spin_lock_init(&gb_dev.lock);
++ gb_dev.root = debugfs_create_dir("gb_loopback", NULL);
++
++ retval = class_register(&loopback_class);
++ if (retval)
++ goto err;
++
++ retval = greybus_register(&gb_loopback_driver);
++ if (retval)
++ goto err_unregister;
++
++ return 0;
++
++err_unregister:
++ class_unregister(&loopback_class);
++err:
++ debugfs_remove_recursive(gb_dev.root);
++ return retval;
++}
++module_init(loopback_init);
++
++static void __exit loopback_exit(void)
++{
++ debugfs_remove_recursive(gb_dev.root);
++ greybus_deregister(&gb_loopback_driver);
++ class_unregister(&loopback_class);
++ ida_destroy(&loopback_ida);
++}
++module_exit(loopback_exit);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_operations.patch b/greybus_operations.patch
new file mode 100644
index 00000000000000..6398656528a23f
--- /dev/null
+++ b/greybus_operations.patch
@@ -0,0 +1,1460 @@
+---
+ drivers/greybus/operation.c | 1239 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/operation.h | 210 +++++++
+ 2 files changed, 1449 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/operation.c
+@@ -0,0 +1,1239 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++
++#include "greybus.h"
++#include "greybus_trace.h"
++
++static struct kmem_cache *gb_operation_cache;
++static struct kmem_cache *gb_message_cache;
++
++/* Workqueue to handle Greybus operation completions. */
++static struct workqueue_struct *gb_operation_completion_wq;
++
++/* Wait queue for synchronous cancellations. */
++static DECLARE_WAIT_QUEUE_HEAD(gb_operation_cancellation_queue);
++
++/*
++ * Protects updates to operation->errno.
++ */
++static DEFINE_SPINLOCK(gb_operations_lock);
++
++static int gb_operation_response_send(struct gb_operation *operation,
++ int errno);
++
++/*
++ * Increment operation active count and add to connection list unless the
++ * connection is going away.
++ *
++ * Caller holds operation reference.
++ */
++static int gb_operation_get_active(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ unsigned long flags;
++
++ spin_lock_irqsave(&connection->lock, flags);
++ switch (connection->state) {
++ case GB_CONNECTION_STATE_ENABLED:
++ break;
++ case GB_CONNECTION_STATE_ENABLED_TX:
++ if (gb_operation_is_incoming(operation))
++ goto err_unlock;
++ break;
++ case GB_CONNECTION_STATE_DISCONNECTING:
++ if (!gb_operation_is_core(operation))
++ goto err_unlock;
++ break;
++ default:
++ goto err_unlock;
++ }
++
++ if (operation->active++ == 0)
++ list_add_tail(&operation->links, &connection->operations);
++
++ trace_gb_operation_get_active(operation);
++
++ spin_unlock_irqrestore(&connection->lock, flags);
++
++ return 0;
++
++err_unlock:
++ spin_unlock_irqrestore(&connection->lock, flags);
++
++ return -ENOTCONN;
++}
++
++/* Caller holds operation reference. */
++static void gb_operation_put_active(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ unsigned long flags;
++
++ spin_lock_irqsave(&connection->lock, flags);
++
++ trace_gb_operation_put_active(operation);
++
++ if (--operation->active == 0) {
++ list_del(&operation->links);
++ if (atomic_read(&operation->waiters))
++ wake_up(&gb_operation_cancellation_queue);
++ }
++ spin_unlock_irqrestore(&connection->lock, flags);
++}
++
++static bool gb_operation_is_active(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ unsigned long flags;
++ bool ret;
++
++ spin_lock_irqsave(&connection->lock, flags);
++ ret = operation->active;
++ spin_unlock_irqrestore(&connection->lock, flags);
++
++ return ret;
++}
++
++/*
++ * Set an operation's result.
++ *
++ * Initially an outgoing operation's errno value is -EBADR.
++ * If no error occurs before sending the request message the only
++ * valid value operation->errno can be set to is -EINPROGRESS,
++ * indicating the request has been (or rather is about to be) sent.
++ * At that point nobody should be looking at the result until the
++ * response arrives.
++ *
++ * The first time the result gets set after the request has been
++ * sent, that result "sticks." That is, if two concurrent threads
++ * race to set the result, the first one wins. The return value
++ * tells the caller whether its result was recorded; if not the
++ * caller has nothing more to do.
++ *
++ * The result value -EILSEQ is reserved to signal an implementation
++ * error; if it's ever observed, the code performing the request has
++ * done something fundamentally wrong. It is an error to try to set
++ * the result to -EBADR, and attempts to do so result in a warning,
++ * and -EILSEQ is used instead. Similarly, the only valid result
++ * value to set for an operation in initial state is -EINPROGRESS.
++ * Attempts to do otherwise will also record a (successful) -EILSEQ
++ * operation result.
++ */
++static bool gb_operation_result_set(struct gb_operation *operation, int result)
++{
++ unsigned long flags;
++ int prev;
++
++ if (result == -EINPROGRESS) {
++ /*
++ * -EINPROGRESS is used to indicate the request is
++ * in flight. It should be the first result value
++ * set after the initial -EBADR. Issue a warning
++ * and record an implementation error if it's
++ * set at any other time.
++ */
++ spin_lock_irqsave(&gb_operations_lock, flags);
++ prev = operation->errno;
++ if (prev == -EBADR)
++ operation->errno = result;
++ else
++ operation->errno = -EILSEQ;
++ spin_unlock_irqrestore(&gb_operations_lock, flags);
++ WARN_ON(prev != -EBADR);
++
++ return true;
++ }
++
++ /*
++ * The first result value set after a request has been sent
++ * will be the final result of the operation. Subsequent
++ * attempts to set the result are ignored.
++ *
++ * Note that -EBADR is a reserved "initial state" result
++ * value. Attempts to set this value result in a warning,
++ * and the result code is set to -EILSEQ instead.
++ */
++ if (WARN_ON(result == -EBADR))
++ result = -EILSEQ; /* Nobody should be setting -EBADR */
++
++ spin_lock_irqsave(&gb_operations_lock, flags);
++ prev = operation->errno;
++ if (prev == -EINPROGRESS)
++ operation->errno = result; /* First and final result */
++ spin_unlock_irqrestore(&gb_operations_lock, flags);
++
++ return prev == -EINPROGRESS;
++}
++
++int gb_operation_result(struct gb_operation *operation)
++{
++ int result = operation->errno;
++
++ WARN_ON(result == -EBADR);
++ WARN_ON(result == -EINPROGRESS);
++
++ return result;
++}
++EXPORT_SYMBOL_GPL(gb_operation_result);
++
++/*
++ * Looks up an outgoing operation on a connection and returns a refcounted
++ * pointer if found, or NULL otherwise.
++ */
++static struct gb_operation *
++gb_operation_find_outgoing(struct gb_connection *connection, u16 operation_id)
++{
++ struct gb_operation *operation;
++ unsigned long flags;
++ bool found = false;
++
++ spin_lock_irqsave(&connection->lock, flags);
++ list_for_each_entry(operation, &connection->operations, links)
++ if (operation->id == operation_id &&
++ !gb_operation_is_incoming(operation)) {
++ gb_operation_get(operation);
++ found = true;
++ break;
++ }
++ spin_unlock_irqrestore(&connection->lock, flags);
++
++ return found ? operation : NULL;
++}
++
++static int gb_message_send(struct gb_message *message, gfp_t gfp)
++{
++ struct gb_connection *connection = message->operation->connection;
++
++ trace_gb_message_send(message);
++ return connection->hd->driver->message_send(connection->hd,
++ connection->hd_cport_id,
++ message,
++ gfp);
++}
++
++/*
++ * Cancel a message we have passed to the host device layer to be sent.
++ */
++static void gb_message_cancel(struct gb_message *message)
++{
++ struct gb_host_device *hd = message->operation->connection->hd;
++
++ hd->driver->message_cancel(message);
++}
++
++static void gb_operation_request_handle(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ int status;
++ int ret;
++
++ if (connection->handler) {
++ status = connection->handler(operation);
++ } else {
++ dev_err(&connection->hd->dev,
++ "%s: unexpected incoming request of type 0x%02x\n",
++ connection->name, operation->type);
++
++ status = -EPROTONOSUPPORT;
++ }
++
++ ret = gb_operation_response_send(operation, status);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: failed to send response %d for type 0x%02x: %d\n",
++ connection->name, status, operation->type, ret);
++ return;
++ }
++}
++
++/*
++ * Process operation work.
++ *
++ * For incoming requests, call the protocol request handler. The operation
++ * result should be -EINPROGRESS at this point.
++ *
++ * For outgoing requests, the operation result value should have
++ * been set before queueing this. The operation callback function
++ * allows the original requester to know the request has completed
++ * and its result is available.
++ */
++static void gb_operation_work(struct work_struct *work)
++{
++ struct gb_operation *operation;
++
++ operation = container_of(work, struct gb_operation, work);
++
++ if (gb_operation_is_incoming(operation))
++ gb_operation_request_handle(operation);
++ else
++ operation->callback(operation);
++
++ gb_operation_put_active(operation);
++ gb_operation_put(operation);
++}
++
++static void gb_operation_message_init(struct gb_host_device *hd,
++ struct gb_message *message, u16 operation_id,
++ size_t payload_size, u8 type)
++{
++ struct gb_operation_msg_hdr *header;
++
++ header = message->buffer;
++
++ message->header = header;
++ message->payload = payload_size ? header + 1 : NULL;
++ message->payload_size = payload_size;
++
++ /*
++ * The type supplied for incoming message buffers will be
++ * GB_REQUEST_TYPE_INVALID. Such buffers will be overwritten by
++ * arriving data so there's no need to initialize the message header.
++ */
++ if (type != GB_REQUEST_TYPE_INVALID) {
++ u16 message_size = (u16)(sizeof(*header) + payload_size);
++
++ /*
++ * For a request, the operation id gets filled in
++ * when the message is sent. For a response, it
++ * will be copied from the request by the caller.
++ *
++ * The result field in a request message must be
++ * zero. It will be set just prior to sending for
++ * a response.
++ */
++ header->size = cpu_to_le16(message_size);
++ header->operation_id = 0;
++ header->type = type;
++ header->result = 0;
++ }
++}
++
++/*
++ * Allocate a message to be used for an operation request or response.
++ * Both types of message contain a common header. The request message
++ * for an outgoing operation is outbound, as is the response message
++ * for an incoming operation. The message header for an outbound
++ * message is partially initialized here.
++ *
++ * The headers for inbound messages don't need to be initialized;
++ * they'll be filled in by arriving data.
++ *
++ * Our message buffers have the following layout:
++ * message header \_ these combined are
++ * message payload / the message size
++ */
++static struct gb_message *
++gb_operation_message_alloc(struct gb_host_device *hd, u8 type,
++ size_t payload_size, gfp_t gfp_flags)
++{
++ struct gb_message *message;
++ struct gb_operation_msg_hdr *header;
++ size_t message_size = payload_size + sizeof(*header);
++
++ if (message_size > hd->buffer_size_max) {
++ dev_warn(&hd->dev, "requested message size too big (%zu > %zu)\n",
++ message_size, hd->buffer_size_max);
++ return NULL;
++ }
++
++ /* Allocate the message structure and buffer. */
++ message = kmem_cache_zalloc(gb_message_cache, gfp_flags);
++ if (!message)
++ return NULL;
++
++ message->buffer = kzalloc(message_size, gfp_flags);
++ if (!message->buffer)
++ goto err_free_message;
++
++ /* Initialize the message. Operation id is filled in later. */
++ gb_operation_message_init(hd, message, 0, payload_size, type);
++
++ return message;
++
++err_free_message:
++ kmem_cache_free(gb_message_cache, message);
++
++ return NULL;
++}
++
++static void gb_operation_message_free(struct gb_message *message)
++{
++ kfree(message->buffer);
++ kmem_cache_free(gb_message_cache, message);
++}
++
++/*
++ * Map an enum gb_operation_status value (which is represented in a
++ * message as a single byte) to an appropriate Linux negative errno.
++ */
++static int gb_operation_status_map(u8 status)
++{
++ switch (status) {
++ case GB_OP_SUCCESS:
++ return 0;
++ case GB_OP_INTERRUPTED:
++ return -EINTR;
++ case GB_OP_TIMEOUT:
++ return -ETIMEDOUT;
++ case GB_OP_NO_MEMORY:
++ return -ENOMEM;
++ case GB_OP_PROTOCOL_BAD:
++ return -EPROTONOSUPPORT;
++ case GB_OP_OVERFLOW:
++ return -EMSGSIZE;
++ case GB_OP_INVALID:
++ return -EINVAL;
++ case GB_OP_RETRY:
++ return -EAGAIN;
++ case GB_OP_NONEXISTENT:
++ return -ENODEV;
++ case GB_OP_MALFUNCTION:
++ return -EILSEQ;
++ case GB_OP_UNKNOWN_ERROR:
++ default:
++ return -EIO;
++ }
++}
++
++/*
++ * Map a Linux errno value (from operation->errno) into the value
++ * that should represent it in a response message status sent
++ * over the wire. Returns an enum gb_operation_status value (which
++ * is represented in a message as a single byte).
++ */
++static u8 gb_operation_errno_map(int errno)
++{
++ switch (errno) {
++ case 0:
++ return GB_OP_SUCCESS;
++ case -EINTR:
++ return GB_OP_INTERRUPTED;
++ case -ETIMEDOUT:
++ return GB_OP_TIMEOUT;
++ case -ENOMEM:
++ return GB_OP_NO_MEMORY;
++ case -EPROTONOSUPPORT:
++ return GB_OP_PROTOCOL_BAD;
++ case -EMSGSIZE:
++ return GB_OP_OVERFLOW; /* Could be underflow too */
++ case -EINVAL:
++ return GB_OP_INVALID;
++ case -EAGAIN:
++ return GB_OP_RETRY;
++ case -EILSEQ:
++ return GB_OP_MALFUNCTION;
++ case -ENODEV:
++ return GB_OP_NONEXISTENT;
++ case -EIO:
++ default:
++ return GB_OP_UNKNOWN_ERROR;
++ }
++}
++
++bool gb_operation_response_alloc(struct gb_operation *operation,
++ size_t response_size, gfp_t gfp)
++{
++ struct gb_host_device *hd = operation->connection->hd;
++ struct gb_operation_msg_hdr *request_header;
++ struct gb_message *response;
++ u8 type;
++
++ type = operation->type | GB_MESSAGE_TYPE_RESPONSE;
++ response = gb_operation_message_alloc(hd, type, response_size, gfp);
++ if (!response)
++ return false;
++ response->operation = operation;
++
++ /*
++ * Size and type get initialized when the message is
++ * allocated. The errno will be set before sending. All
++ * that's left is the operation id, which we copy from the
++ * request message header (as-is, in little-endian order).
++ */
++ request_header = operation->request->header;
++ response->header->operation_id = request_header->operation_id;
++ operation->response = response;
++
++ return true;
++}
++EXPORT_SYMBOL_GPL(gb_operation_response_alloc);
++
++/*
++ * Create a Greybus operation to be sent over the given connection.
++ * The request buffer will be big enough for a payload of the given
++ * size.
++ *
++ * For outgoing requests, the request message's header will be
++ * initialized with the type of the request and the message size.
++ * Outgoing operations must also specify the response buffer size,
++ * which must be sufficient to hold all expected response data. The
++ * response message header will eventually be overwritten, so there's
++ * no need to initialize it here.
++ *
++ * Request messages for incoming operations can arrive in interrupt
++ * context, so they must be allocated with GFP_ATOMIC. In this case
++ * the request buffer will be immediately overwritten, so there is
++ * no need to initialize the message header. Responsibility for
++ * allocating a response buffer lies with the incoming request
++ * handler for a protocol. So we don't allocate that here.
++ *
++ * Returns a pointer to the new operation or a null pointer if an
++ * error occurs.
++ */
++static struct gb_operation *
++gb_operation_create_common(struct gb_connection *connection, u8 type,
++ size_t request_size, size_t response_size,
++ unsigned long op_flags, gfp_t gfp_flags)
++{
++ struct gb_host_device *hd = connection->hd;
++ struct gb_operation *operation;
++
++ operation = kmem_cache_zalloc(gb_operation_cache, gfp_flags);
++ if (!operation)
++ return NULL;
++ operation->connection = connection;
++
++ operation->request = gb_operation_message_alloc(hd, type, request_size,
++ gfp_flags);
++ if (!operation->request)
++ goto err_cache;
++ operation->request->operation = operation;
++
++ /* Allocate the response buffer for outgoing operations */
++ if (!(op_flags & GB_OPERATION_FLAG_INCOMING)) {
++ if (!gb_operation_response_alloc(operation, response_size,
++ gfp_flags)) {
++ goto err_request;
++ }
++ }
++
++ operation->flags = op_flags;
++ operation->type = type;
++ operation->errno = -EBADR; /* Initial value--means "never set" */
++
++ INIT_WORK(&operation->work, gb_operation_work);
++ init_completion(&operation->completion);
++ kref_init(&operation->kref);
++ atomic_set(&operation->waiters, 0);
++
++ return operation;
++
++err_request:
++ gb_operation_message_free(operation->request);
++err_cache:
++ kmem_cache_free(gb_operation_cache, operation);
++
++ return NULL;
++}
++
++/*
++ * Create a new operation associated with the given connection. The
++ * request and response sizes provided are the number of bytes
++ * required to hold the request/response payload only. Both of
++ * these are allowed to be 0. Note that 0x00 is reserved as an
++ * invalid operation type for all protocols, and this is enforced
++ * here.
++ */
++struct gb_operation *
++gb_operation_create_flags(struct gb_connection *connection,
++ u8 type, size_t request_size,
++ size_t response_size, unsigned long flags,
++ gfp_t gfp)
++{
++ struct gb_operation *operation;
++
++ if (WARN_ON_ONCE(type == GB_REQUEST_TYPE_INVALID))
++ return NULL;
++ if (WARN_ON_ONCE(type & GB_MESSAGE_TYPE_RESPONSE))
++ type &= ~GB_MESSAGE_TYPE_RESPONSE;
++
++ if (WARN_ON_ONCE(flags & ~GB_OPERATION_FLAG_USER_MASK))
++ flags &= GB_OPERATION_FLAG_USER_MASK;
++
++ operation = gb_operation_create_common(connection, type,
++ request_size, response_size,
++ flags, gfp);
++ if (operation)
++ trace_gb_operation_create(operation);
++
++ return operation;
++}
++EXPORT_SYMBOL_GPL(gb_operation_create_flags);
++
++struct gb_operation *
++gb_operation_create_core(struct gb_connection *connection,
++ u8 type, size_t request_size,
++ size_t response_size, unsigned long flags,
++ gfp_t gfp)
++{
++ struct gb_operation *operation;
++
++ flags |= GB_OPERATION_FLAG_CORE;
++
++ operation = gb_operation_create_common(connection, type,
++ request_size, response_size,
++ flags, gfp);
++ if (operation)
++ trace_gb_operation_create_core(operation);
++
++ return operation;
++}
++/* Do not export this function. */
++
++size_t gb_operation_get_payload_size_max(struct gb_connection *connection)
++{
++ struct gb_host_device *hd = connection->hd;
++
++ return hd->buffer_size_max - sizeof(struct gb_operation_msg_hdr);
++}
++EXPORT_SYMBOL_GPL(gb_operation_get_payload_size_max);
++
++static struct gb_operation *
++gb_operation_create_incoming(struct gb_connection *connection, u16 id,
++ u8 type, void *data, size_t size)
++{
++ struct gb_operation *operation;
++ size_t request_size;
++ unsigned long flags = GB_OPERATION_FLAG_INCOMING;
++
++ /* Caller has made sure we at least have a message header. */
++ request_size = size - sizeof(struct gb_operation_msg_hdr);
++
++ if (!id)
++ flags |= GB_OPERATION_FLAG_UNIDIRECTIONAL;
++
++ operation = gb_operation_create_common(connection, type,
++ request_size,
++ GB_REQUEST_TYPE_INVALID,
++ flags, GFP_ATOMIC);
++ if (!operation)
++ return NULL;
++
++ operation->id = id;
++ memcpy(operation->request->header, data, size);
++ trace_gb_operation_create_incoming(operation);
++
++ return operation;
++}
++
++/*
++ * Get an additional reference on an operation.
++ */
++void gb_operation_get(struct gb_operation *operation)
++{
++ kref_get(&operation->kref);
++}
++EXPORT_SYMBOL_GPL(gb_operation_get);
++
++/*
++ * Destroy a previously created operation.
++ */
++static void _gb_operation_destroy(struct kref *kref)
++{
++ struct gb_operation *operation;
++
++ operation = container_of(kref, struct gb_operation, kref);
++
++ trace_gb_operation_destroy(operation);
++
++ if (operation->response)
++ gb_operation_message_free(operation->response);
++ gb_operation_message_free(operation->request);
++
++ kmem_cache_free(gb_operation_cache, operation);
++}
++
++/*
++ * Drop a reference on an operation, and destroy it when the last
++ * one is gone.
++ */
++void gb_operation_put(struct gb_operation *operation)
++{
++ if (WARN_ON(!operation))
++ return;
++
++ kref_put(&operation->kref, _gb_operation_destroy);
++}
++EXPORT_SYMBOL_GPL(gb_operation_put);
++
++/* Tell the requester we're done */
++static void gb_operation_sync_callback(struct gb_operation *operation)
++{
++ complete(&operation->completion);
++}
++
++/**
++ * gb_operation_request_send() - send an operation request message
++ * @operation: the operation to initiate
++ * @callback: the operation completion callback
++ * @gfp: the memory flags to use for any allocations
++ *
++ * The caller has filled in any payload so the request message is ready to go.
++ * The callback function supplied will be called when the response message has
++ * arrived, a unidirectional request has been sent, or the operation is
++ * cancelled, indicating that the operation is complete. The callback function
++ * can fetch the result of the operation using gb_operation_result() if
++ * desired.
++ *
++ * Return: 0 if the request was successfully queued in the host-driver queues,
++ * or a negative errno.
++ */
++int gb_operation_request_send(struct gb_operation *operation,
++ gb_operation_callback callback,
++ gfp_t gfp)
++{
++ struct gb_connection *connection = operation->connection;
++ struct gb_operation_msg_hdr *header;
++ unsigned int cycle;
++ int ret;
++
++ if (gb_connection_is_offloaded(connection))
++ return -EBUSY;
++
++ if (!callback)
++ return -EINVAL;
++
++ /*
++ * Record the callback function, which is executed in
++ * non-atomic (workqueue) context when the final result
++ * of an operation has been set.
++ */
++ operation->callback = callback;
++
++ /*
++ * Assign the operation's id, and store it in the request header.
++ * Zero is a reserved operation id for unidirectional operations.
++ */
++ if (gb_operation_is_unidirectional(operation)) {
++ operation->id = 0;
++ } else {
++ cycle = (unsigned int)atomic_inc_return(&connection->op_cycle);
++ operation->id = (u16)(cycle % U16_MAX + 1);
++ }
++
++ header = operation->request->header;
++ header->operation_id = cpu_to_le16(operation->id);
++
++ gb_operation_result_set(operation, -EINPROGRESS);
++
++ /*
++ * Get an extra reference on the operation. It'll be dropped when the
++ * operation completes.
++ */
++ gb_operation_get(operation);
++ ret = gb_operation_get_active(operation);
++ if (ret)
++ goto err_put;
++
++ ret = gb_message_send(operation->request, gfp);
++ if (ret)
++ goto err_put_active;
++
++ return 0;
++
++err_put_active:
++ gb_operation_put_active(operation);
++err_put:
++ gb_operation_put(operation);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_operation_request_send);
++
++/*
++ * Send a synchronous operation. This function is expected to
++ * block, returning only when the response has arrived, (or when an
++ * error is detected. The return value is the result of the
++ * operation.
++ */
++int gb_operation_request_send_sync_timeout(struct gb_operation *operation,
++ unsigned int timeout)
++{
++ int ret;
++ unsigned long timeout_jiffies;
++
++ ret = gb_operation_request_send(operation, gb_operation_sync_callback,
++ GFP_KERNEL);
++ if (ret)
++ return ret;
++
++ if (timeout)
++ timeout_jiffies = msecs_to_jiffies(timeout);
++ else
++ timeout_jiffies = MAX_SCHEDULE_TIMEOUT;
++
++ ret = wait_for_completion_interruptible_timeout(&operation->completion,
++ timeout_jiffies);
++ if (ret < 0) {
++ /* Cancel the operation if interrupted */
++ gb_operation_cancel(operation, -ECANCELED);
++ } else if (ret == 0) {
++ /* Cancel the operation if op timed out */
++ gb_operation_cancel(operation, -ETIMEDOUT);
++ }
++
++ return gb_operation_result(operation);
++}
++EXPORT_SYMBOL_GPL(gb_operation_request_send_sync_timeout);
++
++/*
++ * Send a response for an incoming operation request. A non-zero
++ * errno indicates a failed operation.
++ *
++ * If there is any response payload, the incoming request handler is
++ * responsible for allocating the response message. Otherwise the
++ * it can simply supply the result errno; this function will
++ * allocate the response message if necessary.
++ */
++static int gb_operation_response_send(struct gb_operation *operation,
++ int errno)
++{
++ struct gb_connection *connection = operation->connection;
++ int ret;
++
++ if (!operation->response &&
++ !gb_operation_is_unidirectional(operation)) {
++ if (!gb_operation_response_alloc(operation, 0, GFP_KERNEL))
++ return -ENOMEM;
++ }
++
++ /* Record the result */
++ if (!gb_operation_result_set(operation, errno)) {
++ dev_err(&connection->hd->dev, "request result already set\n");
++ return -EIO; /* Shouldn't happen */
++ }
++
++ /* Sender of request does not care about response. */
++ if (gb_operation_is_unidirectional(operation))
++ return 0;
++
++ /* Reference will be dropped when message has been sent. */
++ gb_operation_get(operation);
++ ret = gb_operation_get_active(operation);
++ if (ret)
++ goto err_put;
++
++ /* Fill in the response header and send it */
++ operation->response->header->result = gb_operation_errno_map(errno);
++
++ ret = gb_message_send(operation->response, GFP_KERNEL);
++ if (ret)
++ goto err_put_active;
++
++ return 0;
++
++err_put_active:
++ gb_operation_put_active(operation);
++err_put:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++/*
++ * This function is called when a message send request has completed.
++ */
++void greybus_message_sent(struct gb_host_device *hd,
++ struct gb_message *message, int status)
++{
++ struct gb_operation *operation = message->operation;
++ struct gb_connection *connection = operation->connection;
++
++ /*
++ * If the message was a response, we just need to drop our
++ * reference to the operation. If an error occurred, report
++ * it.
++ *
++ * For requests, if there's no error and the operation in not
++ * unidirectional, there's nothing more to do until the response
++ * arrives. If an error occurred attempting to send it, or if the
++ * operation is unidrectional, record the result of the operation and
++ * schedule its completion.
++ */
++ if (message == operation->response) {
++ if (status) {
++ dev_err(&connection->hd->dev,
++ "%s: error sending response 0x%02x: %d\n",
++ connection->name, operation->type, status);
++ }
++
++ gb_operation_put_active(operation);
++ gb_operation_put(operation);
++ } else if (status || gb_operation_is_unidirectional(operation)) {
++ if (gb_operation_result_set(operation, status)) {
++ queue_work(gb_operation_completion_wq,
++ &operation->work);
++ }
++ }
++}
++EXPORT_SYMBOL_GPL(greybus_message_sent);
++
++/*
++ * We've received data on a connection, and it doesn't look like a
++ * response, so we assume it's a request.
++ *
++ * This is called in interrupt context, so just copy the incoming
++ * data into the request buffer and handle the rest via workqueue.
++ */
++static void gb_connection_recv_request(struct gb_connection *connection,
++ const struct gb_operation_msg_hdr *header,
++ void *data, size_t size)
++{
++ struct gb_operation *operation;
++ u16 operation_id;
++ u8 type;
++ int ret;
++
++ operation_id = le16_to_cpu(header->operation_id);
++ type = header->type;
++
++ operation = gb_operation_create_incoming(connection, operation_id,
++ type, data, size);
++ if (!operation) {
++ dev_err(&connection->hd->dev,
++ "%s: can't create incoming operation\n",
++ connection->name);
++ return;
++ }
++
++ ret = gb_operation_get_active(operation);
++ if (ret) {
++ gb_operation_put(operation);
++ return;
++ }
++ trace_gb_message_recv_request(operation->request);
++
++ /*
++ * The initial reference to the operation will be dropped when the
++ * request handler returns.
++ */
++ if (gb_operation_result_set(operation, -EINPROGRESS))
++ queue_work(connection->wq, &operation->work);
++}
++
++/*
++ * We've received data that appears to be an operation response
++ * message. Look up the operation, and record that we've received
++ * its response.
++ *
++ * This is called in interrupt context, so just copy the incoming
++ * data into the response buffer and handle the rest via workqueue.
++ */
++static void gb_connection_recv_response(struct gb_connection *connection,
++ const struct gb_operation_msg_hdr *header,
++ void *data, size_t size)
++{
++ struct gb_operation *operation;
++ struct gb_message *message;
++ size_t message_size;
++ u16 operation_id;
++ int errno;
++
++ operation_id = le16_to_cpu(header->operation_id);
++
++ if (!operation_id) {
++ dev_err_ratelimited(&connection->hd->dev,
++ "%s: invalid response id 0 received\n",
++ connection->name);
++ return;
++ }
++
++ operation = gb_operation_find_outgoing(connection, operation_id);
++ if (!operation) {
++ dev_err_ratelimited(&connection->hd->dev,
++ "%s: unexpected response id 0x%04x received\n",
++ connection->name, operation_id);
++ return;
++ }
++
++ errno = gb_operation_status_map(header->result);
++ message = operation->response;
++ message_size = sizeof(*header) + message->payload_size;
++ if (!errno && size > message_size) {
++ dev_err_ratelimited(&connection->hd->dev,
++ "%s: malformed response 0x%02x received (%zu > %zu)\n",
++ connection->name, header->type,
++ size, message_size);
++ errno = -EMSGSIZE;
++ } else if (!errno && size < message_size) {
++ if (gb_operation_short_response_allowed(operation)) {
++ message->payload_size = size - sizeof(*header);
++ } else {
++ dev_err_ratelimited(&connection->hd->dev,
++ "%s: short response 0x%02x received (%zu < %zu)\n",
++ connection->name, header->type,
++ size, message_size);
++ errno = -EMSGSIZE;
++ }
++ }
++
++ /* We must ignore the payload if a bad status is returned */
++ if (errno)
++ size = sizeof(*header);
++
++ /* The rest will be handled in work queue context */
++ if (gb_operation_result_set(operation, errno)) {
++ memcpy(message->buffer, data, size);
++
++ trace_gb_message_recv_response(message);
++
++ queue_work(gb_operation_completion_wq, &operation->work);
++ }
++
++ gb_operation_put(operation);
++}
++
++/*
++ * Handle data arriving on a connection. As soon as we return the
++ * supplied data buffer will be reused (so unless we do something
++ * with, it's effectively dropped).
++ */
++void gb_connection_recv(struct gb_connection *connection,
++ void *data, size_t size)
++{
++ struct gb_operation_msg_hdr header;
++ struct device *dev = &connection->hd->dev;
++ size_t msg_size;
++
++ if (connection->state == GB_CONNECTION_STATE_DISABLED ||
++ gb_connection_is_offloaded(connection)) {
++ dev_warn_ratelimited(dev, "%s: dropping %zu received bytes\n",
++ connection->name, size);
++ return;
++ }
++
++ if (size < sizeof(header)) {
++ dev_err_ratelimited(dev, "%s: short message received\n",
++ connection->name);
++ return;
++ }
++
++ /* Use memcpy as data may be unaligned */
++ memcpy(&header, data, sizeof(header));
++ msg_size = le16_to_cpu(header.size);
++ if (size < msg_size) {
++ dev_err_ratelimited(dev,
++ "%s: incomplete message 0x%04x of type 0x%02x received (%zu < %zu)\n",
++ connection->name,
++ le16_to_cpu(header.operation_id),
++ header.type, size, msg_size);
++ return; /* XXX Should still complete operation */
++ }
++
++ if (header.type & GB_MESSAGE_TYPE_RESPONSE) {
++ gb_connection_recv_response(connection, &header, data,
++ msg_size);
++ } else {
++ gb_connection_recv_request(connection, &header, data,
++ msg_size);
++ }
++}
++
++/*
++ * Cancel an outgoing operation synchronously, and record the given error to
++ * indicate why.
++ */
++void gb_operation_cancel(struct gb_operation *operation, int errno)
++{
++ if (WARN_ON(gb_operation_is_incoming(operation)))
++ return;
++
++ if (gb_operation_result_set(operation, errno)) {
++ gb_message_cancel(operation->request);
++ queue_work(gb_operation_completion_wq, &operation->work);
++ }
++ trace_gb_message_cancel_outgoing(operation->request);
++
++ atomic_inc(&operation->waiters);
++ wait_event(gb_operation_cancellation_queue,
++ !gb_operation_is_active(operation));
++ atomic_dec(&operation->waiters);
++}
++EXPORT_SYMBOL_GPL(gb_operation_cancel);
++
++/*
++ * Cancel an incoming operation synchronously. Called during connection tear
++ * down.
++ */
++void gb_operation_cancel_incoming(struct gb_operation *operation, int errno)
++{
++ if (WARN_ON(!gb_operation_is_incoming(operation)))
++ return;
++
++ if (!gb_operation_is_unidirectional(operation)) {
++ /*
++ * Make sure the request handler has submitted the response
++ * before cancelling it.
++ */
++ flush_work(&operation->work);
++ if (!gb_operation_result_set(operation, errno))
++ gb_message_cancel(operation->response);
++ }
++ trace_gb_message_cancel_incoming(operation->response);
++
++ atomic_inc(&operation->waiters);
++ wait_event(gb_operation_cancellation_queue,
++ !gb_operation_is_active(operation));
++ atomic_dec(&operation->waiters);
++}
++
++/**
++ * gb_operation_sync_timeout() - implement a "simple" synchronous operation
++ * @connection: the Greybus connection to send this to
++ * @type: the type of operation to send
++ * @request: pointer to a memory buffer to copy the request from
++ * @request_size: size of @request
++ * @response: pointer to a memory buffer to copy the response to
++ * @response_size: the size of @response.
++ * @timeout: operation timeout in milliseconds
++ *
++ * This function implements a simple synchronous Greybus operation. It sends
++ * the provided operation request and waits (sleeps) until the corresponding
++ * operation response message has been successfully received, or an error
++ * occurs. @request and @response are buffers to hold the request and response
++ * data respectively, and if they are not NULL, their size must be specified in
++ * @request_size and @response_size.
++ *
++ * If a response payload is to come back, and @response is not NULL,
++ * @response_size number of bytes will be copied into @response if the operation
++ * is successful.
++ *
++ * If there is an error, the response buffer is left alone.
++ */
++int gb_operation_sync_timeout(struct gb_connection *connection, int type,
++ void *request, int request_size,
++ void *response, int response_size,
++ unsigned int timeout)
++{
++ struct gb_operation *operation;
++ int ret;
++
++ if ((response_size && !response) ||
++ (request_size && !request))
++ return -EINVAL;
++
++ operation = gb_operation_create(connection, type,
++ request_size, response_size,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ if (request_size)
++ memcpy(operation->request->payload, request, request_size);
++
++ ret = gb_operation_request_send_sync_timeout(operation, timeout);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: synchronous operation id 0x%04x of type 0x%02x failed: %d\n",
++ connection->name, operation->id, type, ret);
++ } else {
++ if (response_size) {
++ memcpy(response, operation->response->payload,
++ response_size);
++ }
++ }
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_operation_sync_timeout);
++
++/**
++ * gb_operation_unidirectional_timeout() - initiate a unidirectional operation
++ * @connection: connection to use
++ * @type: type of operation to send
++ * @request: memory buffer to copy the request from
++ * @request_size: size of @request
++ * @timeout: send timeout in milliseconds
++ *
++ * Initiate a unidirectional operation by sending a request message and
++ * waiting for it to be acknowledged as sent by the host device.
++ *
++ * Note that successful send of a unidirectional operation does not imply that
++ * the request as actually reached the remote end of the connection.
++ */
++int gb_operation_unidirectional_timeout(struct gb_connection *connection,
++ int type, void *request, int request_size,
++ unsigned int timeout)
++{
++ struct gb_operation *operation;
++ int ret;
++
++ if (request_size && !request)
++ return -EINVAL;
++
++ operation = gb_operation_create_flags(connection, type,
++ request_size, 0,
++ GB_OPERATION_FLAG_UNIDIRECTIONAL,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ if (request_size)
++ memcpy(operation->request->payload, request, request_size);
++
++ ret = gb_operation_request_send_sync_timeout(operation, timeout);
++ if (ret) {
++ dev_err(&connection->hd->dev,
++ "%s: unidirectional operation of type 0x%02x failed: %d\n",
++ connection->name, type, ret);
++ }
++
++ gb_operation_put(operation);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_operation_unidirectional_timeout);
++
++int __init gb_operation_init(void)
++{
++ gb_message_cache = kmem_cache_create("gb_message_cache",
++ sizeof(struct gb_message), 0, 0, NULL);
++ if (!gb_message_cache)
++ return -ENOMEM;
++
++ gb_operation_cache = kmem_cache_create("gb_operation_cache",
++ sizeof(struct gb_operation), 0, 0, NULL);
++ if (!gb_operation_cache)
++ goto err_destroy_message_cache;
++
++ gb_operation_completion_wq = alloc_workqueue("greybus_completion",
++ 0, 0);
++ if (!gb_operation_completion_wq)
++ goto err_destroy_operation_cache;
++
++ return 0;
++
++err_destroy_operation_cache:
++ kmem_cache_destroy(gb_operation_cache);
++ gb_operation_cache = NULL;
++err_destroy_message_cache:
++ kmem_cache_destroy(gb_message_cache);
++ gb_message_cache = NULL;
++
++ return -ENOMEM;
++}
++
++void gb_operation_exit(void)
++{
++ destroy_workqueue(gb_operation_completion_wq);
++ gb_operation_completion_wq = NULL;
++ kmem_cache_destroy(gb_operation_cache);
++ gb_operation_cache = NULL;
++ kmem_cache_destroy(gb_message_cache);
++ gb_message_cache = NULL;
++}
+--- /dev/null
++++ b/drivers/greybus/operation.h
+@@ -0,0 +1,210 @@
++/*
++ * Greybus operations
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __OPERATION_H
++#define __OPERATION_H
++
++#include <linux/completion.h>
++
++struct gb_operation;
++
++/* The default amount of time a request is given to complete */
++#define GB_OPERATION_TIMEOUT_DEFAULT 1000 /* milliseconds */
++
++/*
++ * The top bit of the type in an operation message header indicates
++ * whether the message is a request (bit clear) or response (bit set)
++ */
++#define GB_MESSAGE_TYPE_RESPONSE ((u8)0x80)
++
++enum gb_operation_result {
++ GB_OP_SUCCESS = 0x00,
++ GB_OP_INTERRUPTED = 0x01,
++ GB_OP_TIMEOUT = 0x02,
++ GB_OP_NO_MEMORY = 0x03,
++ GB_OP_PROTOCOL_BAD = 0x04,
++ GB_OP_OVERFLOW = 0x05,
++ GB_OP_INVALID = 0x06,
++ GB_OP_RETRY = 0x07,
++ GB_OP_NONEXISTENT = 0x08,
++ GB_OP_UNKNOWN_ERROR = 0xfe,
++ GB_OP_MALFUNCTION = 0xff,
++};
++
++#define GB_OPERATION_MESSAGE_SIZE_MIN sizeof(struct gb_operation_msg_hdr)
++#define GB_OPERATION_MESSAGE_SIZE_MAX U16_MAX
++
++/*
++ * Protocol code should only examine the payload and payload_size fields, and
++ * host-controller drivers may use the hcpriv field. All other fields are
++ * intended to be private to the operations core code.
++ */
++struct gb_message {
++ struct gb_operation *operation;
++ struct gb_operation_msg_hdr *header;
++
++ void *payload;
++ size_t payload_size;
++
++ void *buffer;
++
++ void *hcpriv;
++};
++
++#define GB_OPERATION_FLAG_INCOMING BIT(0)
++#define GB_OPERATION_FLAG_UNIDIRECTIONAL BIT(1)
++#define GB_OPERATION_FLAG_SHORT_RESPONSE BIT(2)
++#define GB_OPERATION_FLAG_CORE BIT(3)
++
++#define GB_OPERATION_FLAG_USER_MASK (GB_OPERATION_FLAG_SHORT_RESPONSE | \
++ GB_OPERATION_FLAG_UNIDIRECTIONAL)
++
++/*
++ * A Greybus operation is a remote procedure call performed over a
++ * connection between two UniPro interfaces.
++ *
++ * Every operation consists of a request message sent to the other
++ * end of the connection coupled with a reply message returned to
++ * the sender. Every operation has a type, whose interpretation is
++ * dependent on the protocol associated with the connection.
++ *
++ * Only four things in an operation structure are intended to be
++ * directly usable by protocol handlers: the operation's connection
++ * pointer; the operation type; the request message payload (and
++ * size); and the response message payload (and size). Note that a
++ * message with a 0-byte payload has a null message payload pointer.
++ *
++ * In addition, every operation has a result, which is an errno
++ * value. Protocol handlers access the operation result using
++ * gb_operation_result().
++ */
++typedef void (*gb_operation_callback)(struct gb_operation *);
++struct gb_operation {
++ struct gb_connection *connection;
++ struct gb_message *request;
++ struct gb_message *response;
++
++ unsigned long flags;
++ u8 type;
++ u16 id;
++ int errno; /* Operation result */
++
++ struct work_struct work;
++ gb_operation_callback callback;
++ struct completion completion;
++
++ struct kref kref;
++ atomic_t waiters;
++
++ int active;
++ struct list_head links; /* connection->operations */
++};
++
++static inline bool
++gb_operation_is_incoming(struct gb_operation *operation)
++{
++ return operation->flags & GB_OPERATION_FLAG_INCOMING;
++}
++
++static inline bool
++gb_operation_is_unidirectional(struct gb_operation *operation)
++{
++ return operation->flags & GB_OPERATION_FLAG_UNIDIRECTIONAL;
++}
++
++static inline bool
++gb_operation_short_response_allowed(struct gb_operation *operation)
++{
++ return operation->flags & GB_OPERATION_FLAG_SHORT_RESPONSE;
++}
++
++static inline bool gb_operation_is_core(struct gb_operation *operation)
++{
++ return operation->flags & GB_OPERATION_FLAG_CORE;
++}
++
++void gb_connection_recv(struct gb_connection *connection,
++ void *data, size_t size);
++
++int gb_operation_result(struct gb_operation *operation);
++
++size_t gb_operation_get_payload_size_max(struct gb_connection *connection);
++struct gb_operation *
++gb_operation_create_flags(struct gb_connection *connection,
++ u8 type, size_t request_size,
++ size_t response_size, unsigned long flags,
++ gfp_t gfp);
++
++static inline struct gb_operation *
++gb_operation_create(struct gb_connection *connection,
++ u8 type, size_t request_size,
++ size_t response_size, gfp_t gfp)
++{
++ return gb_operation_create_flags(connection, type, request_size,
++ response_size, 0, gfp);
++}
++
++struct gb_operation *
++gb_operation_create_core(struct gb_connection *connection,
++ u8 type, size_t request_size,
++ size_t response_size, unsigned long flags,
++ gfp_t gfp);
++
++void gb_operation_get(struct gb_operation *operation);
++void gb_operation_put(struct gb_operation *operation);
++
++bool gb_operation_response_alloc(struct gb_operation *operation,
++ size_t response_size, gfp_t gfp);
++
++int gb_operation_request_send(struct gb_operation *operation,
++ gb_operation_callback callback,
++ gfp_t gfp);
++int gb_operation_request_send_sync_timeout(struct gb_operation *operation,
++ unsigned int timeout);
++static inline int
++gb_operation_request_send_sync(struct gb_operation *operation)
++{
++ return gb_operation_request_send_sync_timeout(operation,
++ GB_OPERATION_TIMEOUT_DEFAULT);
++}
++
++void gb_operation_cancel(struct gb_operation *operation, int errno);
++void gb_operation_cancel_incoming(struct gb_operation *operation, int errno);
++
++void greybus_message_sent(struct gb_host_device *hd,
++ struct gb_message *message, int status);
++
++int gb_operation_sync_timeout(struct gb_connection *connection, int type,
++ void *request, int request_size,
++ void *response, int response_size,
++ unsigned int timeout);
++int gb_operation_unidirectional_timeout(struct gb_connection *connection,
++ int type, void *request, int request_size,
++ unsigned int timeout);
++
++static inline int gb_operation_sync(struct gb_connection *connection, int type,
++ void *request, int request_size,
++ void *response, int response_size)
++{
++ return gb_operation_sync_timeout(connection, type,
++ request, request_size, response, response_size,
++ GB_OPERATION_TIMEOUT_DEFAULT);
++}
++
++static inline int gb_operation_unidirectional(struct gb_connection *connection,
++ int type, void *request, int request_size)
++{
++ return gb_operation_unidirectional_timeout(connection, type,
++ request, request_size, GB_OPERATION_TIMEOUT_DEFAULT);
++}
++
++int gb_operation_init(void);
++void gb_operation_exit(void);
++
++#endif /* !__OPERATION_H */
diff --git a/greybus_power.patch b/greybus_power.patch
new file mode 100644
index 00000000000000..d1826b130a3e83
--- /dev/null
+++ b/greybus_power.patch
@@ -0,0 +1,1148 @@
+---
+ drivers/greybus/power_supply.c | 1141 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1141 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/power_supply.c
+@@ -0,0 +1,1141 @@
++/*
++ * Power Supply driver for a Greybus module.
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/power_supply.h>
++#include <linux/slab.h>
++
++#include "greybus.h"
++
++#define PROP_MAX 32
++
++struct gb_power_supply_prop {
++ enum power_supply_property prop;
++ u8 gb_prop;
++ int val;
++ int previous_val;
++ bool is_writeable;
++};
++
++struct gb_power_supply {
++ u8 id;
++ bool registered;
++ struct power_supply *psy;
++ struct power_supply_desc desc;
++ char name[64];
++ struct gb_power_supplies *supplies;
++ struct delayed_work work;
++ char *manufacturer;
++ char *model_name;
++ char *serial_number;
++ u8 type;
++ u8 properties_count;
++ u8 properties_count_str;
++ unsigned long last_update;
++ u8 cache_invalid;
++ unsigned int update_interval;
++ bool changed;
++ struct gb_power_supply_prop *props;
++ enum power_supply_property *props_raw;
++ bool pm_acquired;
++ struct mutex supply_lock;
++};
++
++struct gb_power_supplies {
++ struct gb_connection *connection;
++ u8 supplies_count;
++ struct gb_power_supply *supply;
++ struct mutex supplies_lock;
++};
++
++#define to_gb_power_supply(x) power_supply_get_drvdata(x)
++
++/*
++ * General power supply properties that could be absent from various reasons,
++ * like kernel versions or vendor specific versions
++ */
++#ifndef POWER_SUPPLY_PROP_VOLTAGE_BOOT
++ #define POWER_SUPPLY_PROP_VOLTAGE_BOOT -1
++#endif
++#ifndef POWER_SUPPLY_PROP_CURRENT_BOOT
++ #define POWER_SUPPLY_PROP_CURRENT_BOOT -1
++#endif
++#ifndef POWER_SUPPLY_PROP_CALIBRATE
++ #define POWER_SUPPLY_PROP_CALIBRATE -1
++#endif
++
++/* cache time in milliseconds, if cache_time is set to 0 cache is disable */
++static unsigned int cache_time = 1000;
++/*
++ * update interval initial and maximum value, between the two will
++ * back-off exponential
++ */
++static unsigned int update_interval_init = 1 * HZ;
++static unsigned int update_interval_max = 30 * HZ;
++
++struct gb_power_supply_changes {
++ enum power_supply_property prop;
++ u32 tolerance_change;
++ void (*prop_changed)(struct gb_power_supply *gbpsy,
++ struct gb_power_supply_prop *prop);
++};
++
++static void gb_power_supply_state_change(struct gb_power_supply *gbpsy,
++ struct gb_power_supply_prop *prop);
++
++static const struct gb_power_supply_changes psy_props_changes[] = {
++ { .prop = GB_POWER_SUPPLY_PROP_STATUS,
++ .tolerance_change = 0,
++ .prop_changed = gb_power_supply_state_change,
++ },
++ { .prop = GB_POWER_SUPPLY_PROP_TEMP,
++ .tolerance_change = 500,
++ .prop_changed = NULL,
++ },
++ { .prop = GB_POWER_SUPPLY_PROP_ONLINE,
++ .tolerance_change = 0,
++ .prop_changed = NULL,
++ },
++};
++
++static int get_psp_from_gb_prop(int gb_prop, enum power_supply_property *psp)
++{
++ int prop;
++
++ switch (gb_prop) {
++ case GB_POWER_SUPPLY_PROP_STATUS:
++ prop = POWER_SUPPLY_PROP_STATUS;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_TYPE:
++ prop = POWER_SUPPLY_PROP_CHARGE_TYPE;
++ break;
++ case GB_POWER_SUPPLY_PROP_HEALTH:
++ prop = POWER_SUPPLY_PROP_HEALTH;
++ break;
++ case GB_POWER_SUPPLY_PROP_PRESENT:
++ prop = POWER_SUPPLY_PROP_PRESENT;
++ break;
++ case GB_POWER_SUPPLY_PROP_ONLINE:
++ prop = POWER_SUPPLY_PROP_ONLINE;
++ break;
++ case GB_POWER_SUPPLY_PROP_AUTHENTIC:
++ prop = POWER_SUPPLY_PROP_AUTHENTIC;
++ break;
++ case GB_POWER_SUPPLY_PROP_TECHNOLOGY:
++ prop = POWER_SUPPLY_PROP_TECHNOLOGY;
++ break;
++ case GB_POWER_SUPPLY_PROP_CYCLE_COUNT:
++ prop = POWER_SUPPLY_PROP_CYCLE_COUNT;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_MAX:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_MIN:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_NOW:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_AVG:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_OCV:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_OCV;
++ break;
++ case GB_POWER_SUPPLY_PROP_VOLTAGE_BOOT:
++ prop = POWER_SUPPLY_PROP_VOLTAGE_BOOT;
++ break;
++ case GB_POWER_SUPPLY_PROP_CURRENT_MAX:
++ prop = POWER_SUPPLY_PROP_CURRENT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_CURRENT_NOW:
++ prop = POWER_SUPPLY_PROP_CURRENT_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_CURRENT_AVG:
++ prop = POWER_SUPPLY_PROP_CURRENT_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_CURRENT_BOOT:
++ prop = POWER_SUPPLY_PROP_CURRENT_BOOT;
++ break;
++ case GB_POWER_SUPPLY_PROP_POWER_NOW:
++ prop = POWER_SUPPLY_PROP_POWER_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_POWER_AVG:
++ prop = POWER_SUPPLY_PROP_POWER_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
++ prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
++ prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_FULL:
++ prop = POWER_SUPPLY_PROP_CHARGE_FULL;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_EMPTY:
++ prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_NOW:
++ prop = POWER_SUPPLY_PROP_CHARGE_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_AVG:
++ prop = POWER_SUPPLY_PROP_CHARGE_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_COUNTER:
++ prop = POWER_SUPPLY_PROP_CHARGE_COUNTER;
++ break;
++ case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
++ prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT;
++ break;
++ case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
++ prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
++ prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
++ break;
++ case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
++ prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
++ prop = POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
++ prop = POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
++ prop = POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
++ prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN:
++ prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_FULL:
++ prop = POWER_SUPPLY_PROP_ENERGY_FULL;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_EMPTY:
++ prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_NOW:
++ prop = POWER_SUPPLY_PROP_ENERGY_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_ENERGY_AVG:
++ prop = POWER_SUPPLY_PROP_ENERGY_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_CAPACITY:
++ prop = POWER_SUPPLY_PROP_CAPACITY;
++ break;
++ case GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
++ prop = POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN;
++ break;
++ case GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX:
++ prop = POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_CAPACITY_LEVEL:
++ prop = POWER_SUPPLY_PROP_CAPACITY_LEVEL;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP:
++ prop = POWER_SUPPLY_PROP_TEMP;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_MAX:
++ prop = POWER_SUPPLY_PROP_TEMP_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_MIN:
++ prop = POWER_SUPPLY_PROP_TEMP_MIN;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
++ prop = POWER_SUPPLY_PROP_TEMP_ALERT_MIN;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
++ prop = POWER_SUPPLY_PROP_TEMP_ALERT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT:
++ prop = POWER_SUPPLY_PROP_TEMP_AMBIENT;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
++ prop = POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN;
++ break;
++ case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
++ prop = POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX;
++ break;
++ case GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
++ prop = POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
++ prop = POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
++ prop = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW;
++ break;
++ case GB_POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
++ prop = POWER_SUPPLY_PROP_TIME_TO_FULL_AVG;
++ break;
++ case GB_POWER_SUPPLY_PROP_TYPE:
++ prop = POWER_SUPPLY_PROP_TYPE;
++ break;
++ case GB_POWER_SUPPLY_PROP_SCOPE:
++ prop = POWER_SUPPLY_PROP_SCOPE;
++ break;
++ case GB_POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
++ prop = POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT;
++ break;
++ case GB_POWER_SUPPLY_PROP_CALIBRATE:
++ prop = POWER_SUPPLY_PROP_CALIBRATE;
++ break;
++ default:
++ prop = -1;
++ break;
++ }
++
++ if (prop < 0)
++ return prop;
++
++ *psp = (enum power_supply_property)prop;
++
++ return 0;
++}
++
++static struct gb_connection *get_conn_from_psy(struct gb_power_supply *gbpsy)
++{
++ return gbpsy->supplies->connection;
++}
++
++static struct gb_power_supply_prop *get_psy_prop(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp)
++{
++ int i;
++
++ for (i = 0; i < gbpsy->properties_count; i++)
++ if (gbpsy->props[i].prop == psp)
++ return &gbpsy->props[i];
++ return NULL;
++}
++
++static int is_psy_prop_writeable(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp)
++{
++ struct gb_power_supply_prop *prop;
++
++ prop = get_psy_prop(gbpsy, psp);
++ if (!prop)
++ return -ENOENT;
++ return prop->is_writeable ? 1 : 0;
++}
++
++static int is_prop_valint(enum power_supply_property psp)
++{
++ return ((psp < POWER_SUPPLY_PROP_MODEL_NAME) ? 1 : 0);
++}
++
++static void next_interval(struct gb_power_supply *gbpsy)
++{
++ if (gbpsy->update_interval == update_interval_max)
++ return;
++
++ /* do some exponential back-off in the update interval */
++ gbpsy->update_interval *= 2;
++ if (gbpsy->update_interval > update_interval_max)
++ gbpsy->update_interval = update_interval_max;
++}
++
++static void __gb_power_supply_changed(struct gb_power_supply *gbpsy)
++{
++ power_supply_changed(gbpsy->psy);
++}
++
++static void gb_power_supply_state_change(struct gb_power_supply *gbpsy,
++ struct gb_power_supply_prop *prop)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ int ret;
++
++ /*
++ * Check gbpsy->pm_acquired to make sure only one pair of 'get_sync'
++ * and 'put_autosuspend' runtime pm call for state property change.
++ */
++ mutex_lock(&gbpsy->supply_lock);
++
++ if ((prop->val == GB_POWER_SUPPLY_STATUS_CHARGING) &&
++ !gbpsy->pm_acquired) {
++ ret = gb_pm_runtime_get_sync(connection->bundle);
++ if (ret)
++ dev_err(&connection->bundle->dev,
++ "Fail to set wake lock for charging state\n");
++ else
++ gbpsy->pm_acquired = true;
++ } else {
++ if (gbpsy->pm_acquired) {
++ ret = gb_pm_runtime_put_autosuspend(connection->bundle);
++ if (ret)
++ dev_err(&connection->bundle->dev,
++ "Fail to set wake unlock for none charging\n");
++ else
++ gbpsy->pm_acquired = false;
++ }
++ }
++
++ mutex_unlock(&gbpsy->supply_lock);
++}
++
++static void check_changed(struct gb_power_supply *gbpsy,
++ struct gb_power_supply_prop *prop)
++{
++ const struct gb_power_supply_changes *psyc;
++ int val = prop->val;
++ int prev_val = prop->previous_val;
++ bool changed = false;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(psy_props_changes); i++) {
++ psyc = &psy_props_changes[i];
++ if (prop->prop == psyc->prop) {
++ if (!psyc->tolerance_change)
++ changed = true;
++ else if (val < prev_val &&
++ prev_val - val > psyc->tolerance_change)
++ changed = true;
++ else if (val > prev_val &&
++ val - prev_val > psyc->tolerance_change)
++ changed = true;
++
++ if (changed && psyc->prop_changed)
++ psyc->prop_changed(gbpsy, prop);
++
++ if (changed)
++ gbpsy->changed = true;
++ break;
++ }
++ }
++}
++
++static int total_props(struct gb_power_supply *gbpsy)
++{
++ /* this return the intval plus the strval properties */
++ return (gbpsy->properties_count + gbpsy->properties_count_str);
++}
++
++static void prop_append(struct gb_power_supply *gbpsy,
++ enum power_supply_property prop)
++{
++ enum power_supply_property *new_props_raw;
++
++ gbpsy->properties_count_str++;
++ new_props_raw = krealloc(gbpsy->props_raw, total_props(gbpsy) *
++ sizeof(enum power_supply_property),
++ GFP_KERNEL);
++ if (!new_props_raw)
++ return;
++ gbpsy->props_raw = new_props_raw;
++ gbpsy->props_raw[total_props(gbpsy) - 1] = prop;
++}
++
++static int __gb_power_supply_set_name(char *init_name, char *name, size_t len)
++{
++ unsigned int i = 0;
++ int ret = 0;
++ struct power_supply *psy;
++
++ if (!strlen(init_name))
++ init_name = "gb_power_supply";
++ strlcpy(name, init_name, len);
++
++ while ((ret < len) && (psy = power_supply_get_by_name(name))) {
++ power_supply_put(psy);
++
++ ret = snprintf(name, len, "%s_%u", init_name, ++i);
++ }
++ if (ret >= len)
++ return -ENOMEM;
++ return i;
++}
++
++static void _gb_power_supply_append_props(struct gb_power_supply *gbpsy)
++{
++ if (strlen(gbpsy->manufacturer))
++ prop_append(gbpsy, POWER_SUPPLY_PROP_MANUFACTURER);
++ if (strlen(gbpsy->model_name))
++ prop_append(gbpsy, POWER_SUPPLY_PROP_MODEL_NAME);
++ if (strlen(gbpsy->serial_number))
++ prop_append(gbpsy, POWER_SUPPLY_PROP_SERIAL_NUMBER);
++}
++
++static int gb_power_supply_description_get(struct gb_power_supply *gbpsy)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ struct gb_power_supply_get_description_request req;
++ struct gb_power_supply_get_description_response resp;
++ int ret;
++
++ req.psy_id = gbpsy->id;
++
++ ret = gb_operation_sync(connection,
++ GB_POWER_SUPPLY_TYPE_GET_DESCRIPTION,
++ &req, sizeof(req), &resp, sizeof(resp));
++ if (ret < 0)
++ return ret;
++
++ gbpsy->manufacturer = kstrndup(resp.manufacturer, PROP_MAX, GFP_KERNEL);
++ if (!gbpsy->manufacturer)
++ return -ENOMEM;
++ gbpsy->model_name = kstrndup(resp.model, PROP_MAX, GFP_KERNEL);
++ if (!gbpsy->model_name)
++ return -ENOMEM;
++ gbpsy->serial_number = kstrndup(resp.serial_number, PROP_MAX,
++ GFP_KERNEL);
++ if (!gbpsy->serial_number)
++ return -ENOMEM;
++
++ gbpsy->type = le16_to_cpu(resp.type);
++ gbpsy->properties_count = resp.properties_count;
++
++ return 0;
++}
++
++static int gb_power_supply_prop_descriptors_get(struct gb_power_supply *gbpsy)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ struct gb_power_supply_get_property_descriptors_request *req;
++ struct gb_power_supply_get_property_descriptors_response *resp;
++ struct gb_operation *op;
++ u8 props_count = gbpsy->properties_count;
++ enum power_supply_property psp;
++ int ret;
++ int i, r = 0;
++
++ if (props_count == 0)
++ return 0;
++
++ op = gb_operation_create(connection,
++ GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS,
++ sizeof(req), sizeof(*resp) + props_count *
++ sizeof(struct gb_power_supply_props_desc),
++ GFP_KERNEL);
++ if (!op)
++ return -ENOMEM;
++
++ req = op->request->payload;
++ req->psy_id = gbpsy->id;
++
++ ret = gb_operation_request_send_sync(op);
++ if (ret < 0)
++ goto out_put_operation;
++
++ resp = op->response->payload;
++
++ /* validate received properties */
++ for (i = 0; i < props_count; i++) {
++ ret = get_psp_from_gb_prop(resp->props[i].property, &psp);
++ if (ret < 0) {
++ dev_warn(&connection->bundle->dev,
++ "greybus property %u it is not supported by this kernel, dropped\n",
++ resp->props[i].property);
++ gbpsy->properties_count--;
++ }
++ }
++
++ gbpsy->props = kcalloc(gbpsy->properties_count, sizeof(*gbpsy->props),
++ GFP_KERNEL);
++ if (!gbpsy->props) {
++ ret = -ENOMEM;
++ goto out_put_operation;
++ }
++
++ gbpsy->props_raw = kcalloc(gbpsy->properties_count,
++ sizeof(*gbpsy->props_raw), GFP_KERNEL);
++ if (!gbpsy->props_raw) {
++ ret = -ENOMEM;
++ goto out_put_operation;
++ }
++
++ /* Store available properties, skip the ones we do not support */
++ for (i = 0; i < props_count; i++) {
++ ret = get_psp_from_gb_prop(resp->props[i].property, &psp);
++ if (ret < 0) {
++ r++;
++ continue;
++ }
++ gbpsy->props[i - r].prop = psp;
++ gbpsy->props[i - r].gb_prop = resp->props[i].property;
++ gbpsy->props_raw[i - r] = psp;
++ if (resp->props[i].is_writeable)
++ gbpsy->props[i - r].is_writeable = true;
++ }
++
++ /*
++ * now append the properties that we already got information in the
++ * get_description operation. (char * ones)
++ */
++ _gb_power_supply_append_props(gbpsy);
++
++ ret = 0;
++out_put_operation:
++ gb_operation_put(op);
++
++ return ret;
++}
++
++static int __gb_power_supply_property_update(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ struct gb_power_supply_prop *prop;
++ struct gb_power_supply_get_property_request req;
++ struct gb_power_supply_get_property_response resp;
++ int val;
++ int ret;
++
++ prop = get_psy_prop(gbpsy, psp);
++ if (!prop)
++ return -EINVAL;
++ req.psy_id = gbpsy->id;
++ req.property = prop->gb_prop;
++
++ ret = gb_operation_sync(connection, GB_POWER_SUPPLY_TYPE_GET_PROPERTY,
++ &req, sizeof(req), &resp, sizeof(resp));
++ if (ret < 0)
++ return ret;
++
++ val = le32_to_cpu(resp.prop_val);
++ if (val == prop->val)
++ return 0;
++
++ prop->previous_val = prop->val;
++ prop->val = val;
++
++ check_changed(gbpsy, prop);
++
++ return 0;
++}
++
++static int __gb_power_supply_property_get(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ struct gb_power_supply_prop *prop;
++
++ prop = get_psy_prop(gbpsy, psp);
++ if (!prop)
++ return -EINVAL;
++
++ val->intval = prop->val;
++ return 0;
++}
++
++static int __gb_power_supply_property_strval_get(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ switch (psp) {
++ case POWER_SUPPLY_PROP_MODEL_NAME:
++ val->strval = gbpsy->model_name;
++ break;
++ case POWER_SUPPLY_PROP_MANUFACTURER:
++ val->strval = gbpsy->manufacturer;
++ break;
++ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
++ val->strval = gbpsy->serial_number;
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static int _gb_power_supply_property_get(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ int ret;
++
++ /*
++ * Properties of type const char *, were already fetched on
++ * get_description operation and should be cached in gb
++ */
++ if (is_prop_valint(psp))
++ ret = __gb_power_supply_property_get(gbpsy, psp, val);
++ else
++ ret = __gb_power_supply_property_strval_get(gbpsy, psp, val);
++
++ if (ret < 0)
++ dev_err(&connection->bundle->dev, "get property %u\n", psp);
++
++ return 0;
++}
++
++static int is_cache_valid(struct gb_power_supply *gbpsy)
++{
++ /* check if cache is good enough or it has expired */
++ if (gbpsy->cache_invalid) {
++ gbpsy->cache_invalid = 0;
++ return 0;
++ }
++
++ if (gbpsy->last_update &&
++ time_is_after_jiffies(gbpsy->last_update +
++ msecs_to_jiffies(cache_time)))
++ return 1;
++
++ return 0;
++}
++
++static int gb_power_supply_status_get(struct gb_power_supply *gbpsy)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ int ret = 0;
++ int i;
++
++ if (is_cache_valid(gbpsy))
++ return 0;
++
++ ret = gb_pm_runtime_get_sync(connection->bundle);
++ if (ret)
++ return ret;
++
++ for (i = 0; i < gbpsy->properties_count; i++) {
++ ret = __gb_power_supply_property_update(gbpsy,
++ gbpsy->props[i].prop);
++ if (ret < 0)
++ break;
++ }
++
++ if (ret == 0)
++ gbpsy->last_update = jiffies;
++
++ gb_pm_runtime_put_autosuspend(connection->bundle);
++ return ret;
++}
++
++static void gb_power_supply_status_update(struct gb_power_supply *gbpsy)
++{
++ /* check if there a change that need to be reported */
++ gb_power_supply_status_get(gbpsy);
++
++ if (!gbpsy->changed)
++ return;
++
++ gbpsy->update_interval = update_interval_init;
++ __gb_power_supply_changed(gbpsy);
++ gbpsy->changed = false;
++}
++
++static void gb_power_supply_work(struct work_struct *work)
++{
++ struct gb_power_supply *gbpsy = container_of(work,
++ struct gb_power_supply,
++ work.work);
++
++ /*
++ * if the poll interval is not set, disable polling, this is helpful
++ * specially at unregister time.
++ */
++ if (!gbpsy->update_interval)
++ return;
++
++ gb_power_supply_status_update(gbpsy);
++ next_interval(gbpsy);
++ schedule_delayed_work(&gbpsy->work, gbpsy->update_interval);
++}
++
++static int get_property(struct power_supply *b,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ struct gb_power_supply *gbpsy = to_gb_power_supply(b);
++
++ gb_power_supply_status_get(gbpsy);
++
++ return _gb_power_supply_property_get(gbpsy, psp, val);
++}
++
++static int gb_power_supply_property_set(struct gb_power_supply *gbpsy,
++ enum power_supply_property psp,
++ int val)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ struct gb_power_supply_prop *prop;
++ struct gb_power_supply_set_property_request req;
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(connection->bundle);
++ if (ret)
++ return ret;
++
++ prop = get_psy_prop(gbpsy, psp);
++ if (!prop) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ req.psy_id = gbpsy->id;
++ req.property = prop->gb_prop;
++ req.prop_val = cpu_to_le32((s32)val);
++
++ ret = gb_operation_sync(connection, GB_POWER_SUPPLY_TYPE_SET_PROPERTY,
++ &req, sizeof(req), NULL, 0);
++ if (ret < 0)
++ goto out;
++
++ /* cache immediately the new value */
++ prop->val = val;
++
++out:
++ gb_pm_runtime_put_autosuspend(connection->bundle);
++ return ret;
++}
++
++static int set_property(struct power_supply *b,
++ enum power_supply_property psp,
++ const union power_supply_propval *val)
++{
++ struct gb_power_supply *gbpsy = to_gb_power_supply(b);
++
++ return gb_power_supply_property_set(gbpsy, psp, val->intval);
++}
++
++static int property_is_writeable(struct power_supply *b,
++ enum power_supply_property psp)
++{
++ struct gb_power_supply *gbpsy = to_gb_power_supply(b);
++
++ return is_psy_prop_writeable(gbpsy, psp);
++}
++
++static int gb_power_supply_register(struct gb_power_supply *gbpsy)
++{
++ struct gb_connection *connection = get_conn_from_psy(gbpsy);
++ struct power_supply_config cfg = {};
++
++ cfg.drv_data = gbpsy;
++
++ gbpsy->desc.name = gbpsy->name;
++ gbpsy->desc.type = gbpsy->type;
++ gbpsy->desc.properties = gbpsy->props_raw;
++ gbpsy->desc.num_properties = total_props(gbpsy);
++ gbpsy->desc.get_property = get_property;
++ gbpsy->desc.set_property = set_property;
++ gbpsy->desc.property_is_writeable = property_is_writeable;
++
++ gbpsy->psy = power_supply_register(&connection->bundle->dev,
++ &gbpsy->desc, &cfg);
++ return PTR_ERR_OR_ZERO(gbpsy->psy);
++}
++
++static void _gb_power_supply_free(struct gb_power_supply *gbpsy)
++{
++ kfree(gbpsy->serial_number);
++ kfree(gbpsy->model_name);
++ kfree(gbpsy->manufacturer);
++ kfree(gbpsy->props_raw);
++ kfree(gbpsy->props);
++}
++
++static void _gb_power_supply_release(struct gb_power_supply *gbpsy)
++{
++ gbpsy->update_interval = 0;
++
++ cancel_delayed_work_sync(&gbpsy->work);
++
++ if (gbpsy->registered)
++ power_supply_unregister(gbpsy->psy);
++
++ _gb_power_supply_free(gbpsy);
++}
++
++static void _gb_power_supplies_release(struct gb_power_supplies *supplies)
++{
++ int i;
++
++ if (!supplies->supply)
++ return;
++
++ mutex_lock(&supplies->supplies_lock);
++ for (i = 0; i < supplies->supplies_count; i++)
++ _gb_power_supply_release(&supplies->supply[i]);
++ kfree(supplies->supply);
++ mutex_unlock(&supplies->supplies_lock);
++ kfree(supplies);
++}
++
++static int gb_power_supplies_get_count(struct gb_power_supplies *supplies)
++{
++ struct gb_power_supply_get_supplies_response resp;
++ int ret;
++
++ ret = gb_operation_sync(supplies->connection,
++ GB_POWER_SUPPLY_TYPE_GET_SUPPLIES,
++ NULL, 0, &resp, sizeof(resp));
++ if (ret < 0)
++ return ret;
++
++ if (!resp.supplies_count)
++ return -EINVAL;
++
++ supplies->supplies_count = resp.supplies_count;
++
++ return ret;
++}
++
++static int gb_power_supply_config(struct gb_power_supplies *supplies, int id)
++{
++ struct gb_power_supply *gbpsy = &supplies->supply[id];
++ int ret;
++
++ gbpsy->supplies = supplies;
++ gbpsy->id = id;
++
++ ret = gb_power_supply_description_get(gbpsy);
++ if (ret < 0)
++ return ret;
++
++ return gb_power_supply_prop_descriptors_get(gbpsy);
++}
++
++static int gb_power_supply_enable(struct gb_power_supply *gbpsy)
++{
++ int ret;
++
++ /* guarantee that we have an unique name, before register */
++ ret = __gb_power_supply_set_name(gbpsy->model_name, gbpsy->name,
++ sizeof(gbpsy->name));
++ if (ret < 0)
++ return ret;
++
++ mutex_init(&gbpsy->supply_lock);
++
++ ret = gb_power_supply_register(gbpsy);
++ if (ret < 0)
++ return ret;
++
++ gbpsy->update_interval = update_interval_init;
++ INIT_DELAYED_WORK(&gbpsy->work, gb_power_supply_work);
++ schedule_delayed_work(&gbpsy->work, 0);
++
++ /* everything went fine, mark it for release code to know */
++ gbpsy->registered = true;
++
++ return 0;
++}
++
++static int gb_power_supplies_setup(struct gb_power_supplies *supplies)
++{
++ struct gb_connection *connection = supplies->connection;
++ int ret;
++ int i;
++
++ mutex_lock(&supplies->supplies_lock);
++
++ ret = gb_power_supplies_get_count(supplies);
++ if (ret < 0)
++ goto out;
++
++ supplies->supply = kzalloc(supplies->supplies_count *
++ sizeof(struct gb_power_supply),
++ GFP_KERNEL);
++
++ if (!supplies->supply) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ for (i = 0; i < supplies->supplies_count; i++) {
++ ret = gb_power_supply_config(supplies, i);
++ if (ret < 0) {
++ dev_err(&connection->bundle->dev,
++ "Fail to configure supplies devices\n");
++ goto out;
++ }
++ }
++out:
++ mutex_unlock(&supplies->supplies_lock);
++ return ret;
++}
++
++static int gb_power_supplies_register(struct gb_power_supplies *supplies)
++{
++ struct gb_connection *connection = supplies->connection;
++ int ret = 0;
++ int i;
++
++ mutex_lock(&supplies->supplies_lock);
++
++ for (i = 0; i < supplies->supplies_count; i++) {
++ ret = gb_power_supply_enable(&supplies->supply[i]);
++ if (ret < 0) {
++ dev_err(&connection->bundle->dev,
++ "Fail to enable supplies devices\n");
++ break;
++ }
++ }
++
++ mutex_unlock(&supplies->supplies_lock);
++ return ret;
++}
++
++static int gb_supplies_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_power_supplies *supplies = gb_connection_get_data(connection);
++ struct gb_power_supply *gbpsy;
++ struct gb_message *request;
++ struct gb_power_supply_event_request *payload;
++ u8 psy_id;
++ u8 event;
++ int ret = 0;
++
++ if (op->type != GB_POWER_SUPPLY_TYPE_EVENT) {
++ dev_err(&connection->bundle->dev,
++ "Unsupported unsolicited event: %u\n", op->type);
++ return -EINVAL;
++ }
++
++ request = op->request;
++
++ if (request->payload_size < sizeof(*payload)) {
++ dev_err(&connection->bundle->dev,
++ "Wrong event size received (%zu < %zu)\n",
++ request->payload_size, sizeof(*payload));
++ return -EINVAL;
++ }
++
++ payload = request->payload;
++ psy_id = payload->psy_id;
++ mutex_lock(&supplies->supplies_lock);
++ if (psy_id >= supplies->supplies_count ||
++ !supplies->supply[psy_id].registered) {
++ dev_err(&connection->bundle->dev,
++ "Event received for unconfigured power_supply id: %d\n",
++ psy_id);
++ ret = -EINVAL;
++ goto out_unlock;
++ }
++
++ event = payload->event;
++ /*
++ * we will only handle events after setup is done and before release is
++ * running. For that just check update_interval.
++ */
++ gbpsy = &supplies->supply[psy_id];
++ if (!gbpsy->update_interval) {
++ ret = -ESHUTDOWN;
++ goto out_unlock;
++ }
++
++ if (event & GB_POWER_SUPPLY_UPDATE) {
++ /*
++ * we need to make sure we invalidate cache, if not no new
++ * values for the properties will be fetch and the all propose
++ * of this event is missed
++ */
++ gbpsy->cache_invalid = 1;
++ gb_power_supply_status_update(gbpsy);
++ }
++
++out_unlock:
++ mutex_unlock(&supplies->supplies_lock);
++ return ret;
++}
++
++static int gb_power_supply_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_power_supplies *supplies;
++ int ret;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_POWER_SUPPLY)
++ return -ENODEV;
++
++ supplies = kzalloc(sizeof(*supplies), GFP_KERNEL);
++ if (!supplies)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_supplies_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto out;
++ }
++
++ supplies->connection = connection;
++ gb_connection_set_data(connection, supplies);
++
++ mutex_init(&supplies->supplies_lock);
++
++ greybus_set_drvdata(bundle, supplies);
++
++ /* We aren't ready to receive an incoming request yet */
++ ret = gb_connection_enable_tx(connection);
++ if (ret)
++ goto error_connection_destroy;
++
++ ret = gb_power_supplies_setup(supplies);
++ if (ret < 0)
++ goto error_connection_disable;
++
++ /* We are ready to receive an incoming request now, enable RX as well */
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto error_connection_disable;
++
++ ret = gb_power_supplies_register(supplies);
++ if (ret < 0)
++ goto error_connection_disable;
++
++ gb_pm_runtime_put_autosuspend(bundle);
++ return 0;
++
++error_connection_disable:
++ gb_connection_disable(connection);
++error_connection_destroy:
++ gb_connection_destroy(connection);
++out:
++ _gb_power_supplies_release(supplies);
++ return ret;
++}
++
++static void gb_power_supply_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_power_supplies *supplies = greybus_get_drvdata(bundle);
++
++ gb_connection_disable(supplies->connection);
++ gb_connection_destroy(supplies->connection);
++
++ _gb_power_supplies_release(supplies);
++}
++
++static const struct greybus_bundle_id gb_power_supply_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_power_supply_id_table);
++
++static struct greybus_driver gb_power_supply_driver = {
++ .name = "power_supply",
++ .probe = gb_power_supply_probe,
++ .disconnect = gb_power_supply_disconnect,
++ .id_table = gb_power_supply_id_table,
++};
++module_greybus_driver(gb_power_supply_driver);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_protocol.patch b/greybus_protocol.patch
new file mode 100644
index 00000000000000..7efe2c2259c1a8
--- /dev/null
+++ b/greybus_protocol.patch
@@ -0,0 +1,2275 @@
+---
+ drivers/greybus/greybus_protocols.h | 2268 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 2268 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/greybus_protocols.h
+@@ -0,0 +1,2268 @@
++/*
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2014 - 2015 Google Inc. All rights reserved.
++ * Copyright(c) 2014 - 2015 Linaro Ltd. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 for more details.
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2014 - 2015 Google Inc. All rights reserved.
++ * Copyright(c) 2014 - 2015 Linaro Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Google Inc. or Linaro Ltd. nor the names of
++ * its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written
++ * permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
++ * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __GREYBUS_PROTOCOLS_H
++#define __GREYBUS_PROTOCOLS_H
++
++/* Fixed IDs for control/svc protocols */
++
++/* SVC switch-port device ids */
++#define GB_SVC_DEVICE_ID_SVC 0
++#define GB_SVC_DEVICE_ID_AP 1
++#define GB_SVC_DEVICE_ID_MIN 2
++#define GB_SVC_DEVICE_ID_MAX 31
++
++#define GB_SVC_CPORT_ID 0
++#define GB_CONTROL_BUNDLE_ID 0
++#define GB_CONTROL_CPORT_ID 0
++
++
++/*
++ * All operation messages (both requests and responses) begin with
++ * a header that encodes the size of the message (header included).
++ * This header also contains a unique identifier, that associates a
++ * response message with its operation. The header contains an
++ * operation type field, whose interpretation is dependent on what
++ * type of protocol is used over the connection. The high bit
++ * (0x80) of the operation type field is used to indicate whether
++ * the message is a request (clear) or a response (set).
++ *
++ * Response messages include an additional result byte, which
++ * communicates the result of the corresponding request. A zero
++ * result value means the operation completed successfully. Any
++ * other value indicates an error; in this case, the payload of the
++ * response message (if any) is ignored. The result byte must be
++ * zero in the header for a request message.
++ *
++ * The wire format for all numeric fields in the header is little
++ * endian. Any operation-specific data begins immediately after the
++ * header.
++ */
++struct gb_operation_msg_hdr {
++ __le16 size; /* Size in bytes of header + payload */
++ __le16 operation_id; /* Operation unique id */
++ __u8 type; /* E.g GB_I2C_TYPE_* or GB_GPIO_TYPE_* */
++ __u8 result; /* Result of request (in responses only) */
++ __u8 pad[2]; /* must be zero (ignore when read) */
++} __packed;
++
++
++/* Generic request types */
++#define GB_REQUEST_TYPE_CPORT_SHUTDOWN 0x00
++#define GB_REQUEST_TYPE_INVALID 0x7f
++
++struct gb_cport_shutdown_request {
++ __u8 phase;
++} __packed;
++
++
++/* Control Protocol */
++
++/* Greybus control request types */
++#define GB_CONTROL_TYPE_VERSION 0x01
++#define GB_CONTROL_TYPE_PROBE_AP 0x02
++#define GB_CONTROL_TYPE_GET_MANIFEST_SIZE 0x03
++#define GB_CONTROL_TYPE_GET_MANIFEST 0x04
++#define GB_CONTROL_TYPE_CONNECTED 0x05
++#define GB_CONTROL_TYPE_DISCONNECTED 0x06
++#define GB_CONTROL_TYPE_TIMESYNC_ENABLE 0x07
++#define GB_CONTROL_TYPE_TIMESYNC_DISABLE 0x08
++#define GB_CONTROL_TYPE_TIMESYNC_AUTHORITATIVE 0x09
++/* Unused 0x0a */
++#define GB_CONTROL_TYPE_BUNDLE_VERSION 0x0b
++#define GB_CONTROL_TYPE_DISCONNECTING 0x0c
++#define GB_CONTROL_TYPE_TIMESYNC_GET_LAST_EVENT 0x0d
++#define GB_CONTROL_TYPE_MODE_SWITCH 0x0e
++#define GB_CONTROL_TYPE_BUNDLE_SUSPEND 0x0f
++#define GB_CONTROL_TYPE_BUNDLE_RESUME 0x10
++#define GB_CONTROL_TYPE_BUNDLE_DEACTIVATE 0x11
++#define GB_CONTROL_TYPE_BUNDLE_ACTIVATE 0x12
++#define GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE 0x13
++#define GB_CONTROL_TYPE_INTF_DEACTIVATE_PREPARE 0x14
++#define GB_CONTROL_TYPE_INTF_HIBERNATE_ABORT 0x15
++
++struct gb_control_version_request {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++struct gb_control_version_response {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++struct gb_control_bundle_version_request {
++ __u8 bundle_id;
++} __packed;
++
++struct gb_control_bundle_version_response {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++/* Control protocol manifest get size request has no payload*/
++struct gb_control_get_manifest_size_response {
++ __le16 size;
++} __packed;
++
++/* Control protocol manifest get request has no payload */
++struct gb_control_get_manifest_response {
++ __u8 data[0];
++} __packed;
++
++/* Control protocol [dis]connected request */
++struct gb_control_connected_request {
++ __le16 cport_id;
++} __packed;
++
++struct gb_control_disconnecting_request {
++ __le16 cport_id;
++} __packed;
++/* disconnecting response has no payload */
++
++struct gb_control_disconnected_request {
++ __le16 cport_id;
++} __packed;
++/* Control protocol [dis]connected response has no payload */
++
++#define GB_TIMESYNC_MAX_STROBES 0x04
++
++struct gb_control_timesync_enable_request {
++ __u8 count;
++ __le64 frame_time;
++ __le32 strobe_delay;
++ __le32 refclk;
++} __packed;
++/* timesync enable response has no payload */
++
++struct gb_control_timesync_authoritative_request {
++ __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
++} __packed;
++/* timesync authoritative response has no payload */
++
++/* timesync get_last_event_request has no payload */
++struct gb_control_timesync_get_last_event_response {
++ __le64 frame_time;
++} __packed;
++
++/*
++ * All Bundle power management operations use the same request and response
++ * layout and status codes.
++ */
++
++#define GB_CONTROL_BUNDLE_PM_OK 0x00
++#define GB_CONTROL_BUNDLE_PM_INVAL 0x01
++#define GB_CONTROL_BUNDLE_PM_BUSY 0x02
++#define GB_CONTROL_BUNDLE_PM_FAIL 0x03
++#define GB_CONTROL_BUNDLE_PM_NA 0x04
++
++struct gb_control_bundle_pm_request {
++ __u8 bundle_id;
++} __packed;
++
++struct gb_control_bundle_pm_response {
++ __u8 status;
++} __packed;
++
++/*
++ * Interface Suspend Prepare and Deactivate Prepare operations use the same
++ * response layout and error codes. Define a single response structure and reuse
++ * it. Both operations have no payload.
++ */
++
++#define GB_CONTROL_INTF_PM_OK 0x00
++#define GB_CONTROL_INTF_PM_BUSY 0x01
++#define GB_CONTROL_INTF_PM_NA 0x02
++
++struct gb_control_intf_pm_response {
++ __u8 status;
++} __packed;
++
++/* APBridge protocol */
++
++/* request APB1 log */
++#define GB_APB_REQUEST_LOG 0x02
++
++/* request to map a cport to bulk in and bulk out endpoints */
++#define GB_APB_REQUEST_EP_MAPPING 0x03
++
++/* request to get the number of cports available */
++#define GB_APB_REQUEST_CPORT_COUNT 0x04
++
++/* request to reset a cport state */
++#define GB_APB_REQUEST_RESET_CPORT 0x05
++
++/* request to time the latency of messages on a given cport */
++#define GB_APB_REQUEST_LATENCY_TAG_EN 0x06
++#define GB_APB_REQUEST_LATENCY_TAG_DIS 0x07
++
++/* request to control the CSI transmitter */
++#define GB_APB_REQUEST_CSI_TX_CONTROL 0x08
++
++/* request to control audio streaming */
++#define GB_APB_REQUEST_AUDIO_CONTROL 0x09
++
++/* TimeSync requests */
++#define GB_APB_REQUEST_TIMESYNC_ENABLE 0x0d
++#define GB_APB_REQUEST_TIMESYNC_DISABLE 0x0e
++#define GB_APB_REQUEST_TIMESYNC_AUTHORITATIVE 0x0f
++#define GB_APB_REQUEST_TIMESYNC_GET_LAST_EVENT 0x10
++
++/* requests to set Greybus CPort flags */
++#define GB_APB_REQUEST_CPORT_FLAGS 0x11
++
++/* ARPC request */
++#define GB_APB_REQUEST_ARPC_RUN 0x12
++
++struct gb_apb_request_cport_flags {
++ __le32 flags;
++#define GB_APB_CPORT_FLAG_CONTROL 0x01
++#define GB_APB_CPORT_FLAG_HIGH_PRIO 0x02
++} __packed;
++
++
++/* Firmware Download Protocol */
++
++/* Request Types */
++#define GB_FW_DOWNLOAD_TYPE_FIND_FIRMWARE 0x01
++#define GB_FW_DOWNLOAD_TYPE_FETCH_FIRMWARE 0x02
++#define GB_FW_DOWNLOAD_TYPE_RELEASE_FIRMWARE 0x03
++
++#define GB_FIRMWARE_TAG_MAX_SIZE 10
++
++/* firmware download find firmware request/response */
++struct gb_fw_download_find_firmware_request {
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++} __packed;
++
++struct gb_fw_download_find_firmware_response {
++ __u8 firmware_id;
++ __le32 size;
++} __packed;
++
++/* firmware download fetch firmware request/response */
++struct gb_fw_download_fetch_firmware_request {
++ __u8 firmware_id;
++ __le32 offset;
++ __le32 size;
++} __packed;
++
++struct gb_fw_download_fetch_firmware_response {
++ __u8 data[0];
++} __packed;
++
++/* firmware download release firmware request */
++struct gb_fw_download_release_firmware_request {
++ __u8 firmware_id;
++} __packed;
++/* firmware download release firmware response has no payload */
++
++
++/* Firmware Management Protocol */
++
++/* Request Types */
++#define GB_FW_MGMT_TYPE_INTERFACE_FW_VERSION 0x01
++#define GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW 0x02
++#define GB_FW_MGMT_TYPE_LOADED_FW 0x03
++#define GB_FW_MGMT_TYPE_BACKEND_FW_VERSION 0x04
++#define GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE 0x05
++#define GB_FW_MGMT_TYPE_BACKEND_FW_UPDATED 0x06
++
++#define GB_FW_LOAD_METHOD_UNIPRO 0x01
++#define GB_FW_LOAD_METHOD_INTERNAL 0x02
++
++#define GB_FW_LOAD_STATUS_FAILED 0x00
++#define GB_FW_LOAD_STATUS_UNVALIDATED 0x01
++#define GB_FW_LOAD_STATUS_VALIDATED 0x02
++#define GB_FW_LOAD_STATUS_VALIDATION_FAILED 0x03
++
++#define GB_FW_BACKEND_FW_STATUS_SUCCESS 0x01
++#define GB_FW_BACKEND_FW_STATUS_FAIL_FIND 0x02
++#define GB_FW_BACKEND_FW_STATUS_FAIL_FETCH 0x03
++#define GB_FW_BACKEND_FW_STATUS_FAIL_WRITE 0x04
++#define GB_FW_BACKEND_FW_STATUS_INT 0x05
++#define GB_FW_BACKEND_FW_STATUS_RETRY 0x06
++#define GB_FW_BACKEND_FW_STATUS_NOT_SUPPORTED 0x07
++
++#define GB_FW_BACKEND_VERSION_STATUS_SUCCESS 0x01
++#define GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE 0x02
++#define GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED 0x03
++#define GB_FW_BACKEND_VERSION_STATUS_RETRY 0x04
++#define GB_FW_BACKEND_VERSION_STATUS_FAIL_INT 0x05
++
++/* firmware management interface firmware version request has no payload */
++struct gb_fw_mgmt_interface_fw_version_response {
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++ __le16 major;
++ __le16 minor;
++} __packed;
++
++/* firmware management load and validate firmware request/response */
++struct gb_fw_mgmt_load_and_validate_fw_request {
++ __u8 request_id;
++ __u8 load_method;
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++} __packed;
++/* firmware management load and validate firmware response has no payload*/
++
++/* firmware management loaded firmware request */
++struct gb_fw_mgmt_loaded_fw_request {
++ __u8 request_id;
++ __u8 status;
++ __le16 major;
++ __le16 minor;
++} __packed;
++/* firmware management loaded firmware response has no payload */
++
++/* firmware management backend firmware version request/response */
++struct gb_fw_mgmt_backend_fw_version_request {
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++} __packed;
++
++struct gb_fw_mgmt_backend_fw_version_response {
++ __le16 major;
++ __le16 minor;
++ __u8 status;
++} __packed;
++
++/* firmware management backend firmware update request */
++struct gb_fw_mgmt_backend_fw_update_request {
++ __u8 request_id;
++ __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE];
++} __packed;
++/* firmware management backend firmware update response has no payload */
++
++/* firmware management backend firmware updated request */
++struct gb_fw_mgmt_backend_fw_updated_request {
++ __u8 request_id;
++ __u8 status;
++} __packed;
++/* firmware management backend firmware updated response has no payload */
++
++
++/* Component Authentication Protocol (CAP) */
++
++/* Request Types */
++#define GB_CAP_TYPE_GET_ENDPOINT_UID 0x01
++#define GB_CAP_TYPE_GET_IMS_CERTIFICATE 0x02
++#define GB_CAP_TYPE_AUTHENTICATE 0x03
++
++/* CAP get endpoint uid request has no payload */
++struct gb_cap_get_endpoint_uid_response {
++ __u8 uid[8];
++} __packed;
++
++/* CAP get endpoint ims certificate request/response */
++struct gb_cap_get_ims_certificate_request {
++ __le32 certificate_class;
++ __le32 certificate_id;
++} __packed;
++
++struct gb_cap_get_ims_certificate_response {
++ __u8 result_code;
++ __u8 certificate[0];
++} __packed;
++
++/* CAP authenticate request/response */
++struct gb_cap_authenticate_request {
++ __le32 auth_type;
++ __u8 uid[8];
++ __u8 challenge[32];
++} __packed;
++
++struct gb_cap_authenticate_response {
++ __u8 result_code;
++ __u8 response[64];
++ __u8 signature[0];
++} __packed;
++
++
++/* Bootrom Protocol */
++
++/* Version of the Greybus bootrom protocol we support */
++#define GB_BOOTROM_VERSION_MAJOR 0x00
++#define GB_BOOTROM_VERSION_MINOR 0x01
++
++/* Greybus bootrom request types */
++#define GB_BOOTROM_TYPE_VERSION 0x01
++#define GB_BOOTROM_TYPE_FIRMWARE_SIZE 0x02
++#define GB_BOOTROM_TYPE_GET_FIRMWARE 0x03
++#define GB_BOOTROM_TYPE_READY_TO_BOOT 0x04
++#define GB_BOOTROM_TYPE_AP_READY 0x05 /* Request with no-payload */
++#define GB_BOOTROM_TYPE_GET_VID_PID 0x06 /* Request with no-payload */
++
++/* Greybus bootrom boot stages */
++#define GB_BOOTROM_BOOT_STAGE_ONE 0x01 /* Reserved for the boot ROM */
++#define GB_BOOTROM_BOOT_STAGE_TWO 0x02 /* Bootrom package to be loaded by the boot ROM */
++#define GB_BOOTROM_BOOT_STAGE_THREE 0x03 /* Module personality package loaded by Stage 2 firmware */
++
++/* Greybus bootrom ready to boot status */
++#define GB_BOOTROM_BOOT_STATUS_INVALID 0x00 /* Firmware blob could not be validated */
++#define GB_BOOTROM_BOOT_STATUS_INSECURE 0x01 /* Firmware blob is valid but insecure */
++#define GB_BOOTROM_BOOT_STATUS_SECURE 0x02 /* Firmware blob is valid and secure */
++
++/* Max bootrom data fetch size in bytes */
++#define GB_BOOTROM_FETCH_MAX 2000
++
++struct gb_bootrom_version_request {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++struct gb_bootrom_version_response {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++/* Bootrom protocol firmware size request/response */
++struct gb_bootrom_firmware_size_request {
++ __u8 stage;
++} __packed;
++
++struct gb_bootrom_firmware_size_response {
++ __le32 size;
++} __packed;
++
++/* Bootrom protocol get firmware request/response */
++struct gb_bootrom_get_firmware_request {
++ __le32 offset;
++ __le32 size;
++} __packed;
++
++struct gb_bootrom_get_firmware_response {
++ __u8 data[0];
++} __packed;
++
++/* Bootrom protocol Ready to boot request */
++struct gb_bootrom_ready_to_boot_request {
++ __u8 status;
++} __packed;
++/* Bootrom protocol Ready to boot response has no payload */
++
++/* Bootrom protocol get VID/PID request has no payload */
++struct gb_bootrom_get_vid_pid_response {
++ __le32 vendor_id;
++ __le32 product_id;
++} __packed;
++
++
++/* Power Supply */
++
++/* Greybus power supply request types */
++#define GB_POWER_SUPPLY_TYPE_GET_SUPPLIES 0x02
++#define GB_POWER_SUPPLY_TYPE_GET_DESCRIPTION 0x03
++#define GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS 0x04
++#define GB_POWER_SUPPLY_TYPE_GET_PROPERTY 0x05
++#define GB_POWER_SUPPLY_TYPE_SET_PROPERTY 0x06
++#define GB_POWER_SUPPLY_TYPE_EVENT 0x07
++
++/* Greybus power supply battery technologies types */
++#define GB_POWER_SUPPLY_TECH_UNKNOWN 0x0000
++#define GB_POWER_SUPPLY_TECH_NiMH 0x0001
++#define GB_POWER_SUPPLY_TECH_LION 0x0002
++#define GB_POWER_SUPPLY_TECH_LIPO 0x0003
++#define GB_POWER_SUPPLY_TECH_LiFe 0x0004
++#define GB_POWER_SUPPLY_TECH_NiCd 0x0005
++#define GB_POWER_SUPPLY_TECH_LiMn 0x0006
++
++/* Greybus power supply types */
++#define GB_POWER_SUPPLY_UNKNOWN_TYPE 0x0000
++#define GB_POWER_SUPPLY_BATTERY_TYPE 0x0001
++#define GB_POWER_SUPPLY_UPS_TYPE 0x0002
++#define GB_POWER_SUPPLY_MAINS_TYPE 0x0003
++#define GB_POWER_SUPPLY_USB_TYPE 0x0004
++#define GB_POWER_SUPPLY_USB_DCP_TYPE 0x0005
++#define GB_POWER_SUPPLY_USB_CDP_TYPE 0x0006
++#define GB_POWER_SUPPLY_USB_ACA_TYPE 0x0007
++
++/* Greybus power supply health values */
++#define GB_POWER_SUPPLY_HEALTH_UNKNOWN 0x0000
++#define GB_POWER_SUPPLY_HEALTH_GOOD 0x0001
++#define GB_POWER_SUPPLY_HEALTH_OVERHEAT 0x0002
++#define GB_POWER_SUPPLY_HEALTH_DEAD 0x0003
++#define GB_POWER_SUPPLY_HEALTH_OVERVOLTAGE 0x0004
++#define GB_POWER_SUPPLY_HEALTH_UNSPEC_FAILURE 0x0005
++#define GB_POWER_SUPPLY_HEALTH_COLD 0x0006
++#define GB_POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE 0x0007
++#define GB_POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE 0x0008
++
++/* Greybus power supply status values */
++#define GB_POWER_SUPPLY_STATUS_UNKNOWN 0x0000
++#define GB_POWER_SUPPLY_STATUS_CHARGING 0x0001
++#define GB_POWER_SUPPLY_STATUS_DISCHARGING 0x0002
++#define GB_POWER_SUPPLY_STATUS_NOT_CHARGING 0x0003
++#define GB_POWER_SUPPLY_STATUS_FULL 0x0004
++
++/* Greybus power supply capacity level values */
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN 0x0000
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL 0x0001
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_LOW 0x0002
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_NORMAL 0x0003
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_HIGH 0x0004
++#define GB_POWER_SUPPLY_CAPACITY_LEVEL_FULL 0x0005
++
++/* Greybus power supply scope values */
++#define GB_POWER_SUPPLY_SCOPE_UNKNOWN 0x0000
++#define GB_POWER_SUPPLY_SCOPE_SYSTEM 0x0001
++#define GB_POWER_SUPPLY_SCOPE_DEVICE 0x0002
++
++struct gb_power_supply_get_supplies_response {
++ __u8 supplies_count;
++} __packed;
++
++struct gb_power_supply_get_description_request {
++ __u8 psy_id;
++} __packed;
++
++struct gb_power_supply_get_description_response {
++ __u8 manufacturer[32];
++ __u8 model[32];
++ __u8 serial_number[32];
++ __le16 type;
++ __u8 properties_count;
++} __packed;
++
++struct gb_power_supply_props_desc {
++ __u8 property;
++#define GB_POWER_SUPPLY_PROP_STATUS 0x00
++#define GB_POWER_SUPPLY_PROP_CHARGE_TYPE 0x01
++#define GB_POWER_SUPPLY_PROP_HEALTH 0x02
++#define GB_POWER_SUPPLY_PROP_PRESENT 0x03
++#define GB_POWER_SUPPLY_PROP_ONLINE 0x04
++#define GB_POWER_SUPPLY_PROP_AUTHENTIC 0x05
++#define GB_POWER_SUPPLY_PROP_TECHNOLOGY 0x06
++#define GB_POWER_SUPPLY_PROP_CYCLE_COUNT 0x07
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_MAX 0x08
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_MIN 0x09
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN 0x0A
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN 0x0B
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_NOW 0x0C
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_AVG 0x0D
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_OCV 0x0E
++#define GB_POWER_SUPPLY_PROP_VOLTAGE_BOOT 0x0F
++#define GB_POWER_SUPPLY_PROP_CURRENT_MAX 0x10
++#define GB_POWER_SUPPLY_PROP_CURRENT_NOW 0x11
++#define GB_POWER_SUPPLY_PROP_CURRENT_AVG 0x12
++#define GB_POWER_SUPPLY_PROP_CURRENT_BOOT 0x13
++#define GB_POWER_SUPPLY_PROP_POWER_NOW 0x14
++#define GB_POWER_SUPPLY_PROP_POWER_AVG 0x15
++#define GB_POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN 0x16
++#define GB_POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN 0x17
++#define GB_POWER_SUPPLY_PROP_CHARGE_FULL 0x18
++#define GB_POWER_SUPPLY_PROP_CHARGE_EMPTY 0x19
++#define GB_POWER_SUPPLY_PROP_CHARGE_NOW 0x1A
++#define GB_POWER_SUPPLY_PROP_CHARGE_AVG 0x1B
++#define GB_POWER_SUPPLY_PROP_CHARGE_COUNTER 0x1C
++#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT 0x1D
++#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX 0x1E
++#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE 0x1F
++#define GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX 0x20
++#define GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT 0x21
++#define GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX 0x22
++#define GB_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT 0x23
++#define GB_POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN 0x24
++#define GB_POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN 0x25
++#define GB_POWER_SUPPLY_PROP_ENERGY_FULL 0x26
++#define GB_POWER_SUPPLY_PROP_ENERGY_EMPTY 0x27
++#define GB_POWER_SUPPLY_PROP_ENERGY_NOW 0x28
++#define GB_POWER_SUPPLY_PROP_ENERGY_AVG 0x29
++#define GB_POWER_SUPPLY_PROP_CAPACITY 0x2A
++#define GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN 0x2B
++#define GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX 0x2C
++#define GB_POWER_SUPPLY_PROP_CAPACITY_LEVEL 0x2D
++#define GB_POWER_SUPPLY_PROP_TEMP 0x2E
++#define GB_POWER_SUPPLY_PROP_TEMP_MAX 0x2F
++#define GB_POWER_SUPPLY_PROP_TEMP_MIN 0x30
++#define GB_POWER_SUPPLY_PROP_TEMP_ALERT_MIN 0x31
++#define GB_POWER_SUPPLY_PROP_TEMP_ALERT_MAX 0x32
++#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT 0x33
++#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN 0x34
++#define GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX 0x35
++#define GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW 0x36
++#define GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG 0x37
++#define GB_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW 0x38
++#define GB_POWER_SUPPLY_PROP_TIME_TO_FULL_AVG 0x39
++#define GB_POWER_SUPPLY_PROP_TYPE 0x3A
++#define GB_POWER_SUPPLY_PROP_SCOPE 0x3B
++#define GB_POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT 0x3C
++#define GB_POWER_SUPPLY_PROP_CALIBRATE 0x3D
++ __u8 is_writeable;
++} __packed;
++
++struct gb_power_supply_get_property_descriptors_request {
++ __u8 psy_id;
++} __packed;
++
++struct gb_power_supply_get_property_descriptors_response {
++ __u8 properties_count;
++ struct gb_power_supply_props_desc props[];
++} __packed;
++
++struct gb_power_supply_get_property_request {
++ __u8 psy_id;
++ __u8 property;
++} __packed;
++
++struct gb_power_supply_get_property_response {
++ __le32 prop_val;
++};
++
++struct gb_power_supply_set_property_request {
++ __u8 psy_id;
++ __u8 property;
++ __le32 prop_val;
++} __packed;
++
++struct gb_power_supply_event_request {
++ __u8 psy_id;
++ __u8 event;
++#define GB_POWER_SUPPLY_UPDATE 0x01
++} __packed;
++
++
++/* HID */
++
++/* Greybus HID operation types */
++#define GB_HID_TYPE_GET_DESC 0x02
++#define GB_HID_TYPE_GET_REPORT_DESC 0x03
++#define GB_HID_TYPE_PWR_ON 0x04
++#define GB_HID_TYPE_PWR_OFF 0x05
++#define GB_HID_TYPE_GET_REPORT 0x06
++#define GB_HID_TYPE_SET_REPORT 0x07
++#define GB_HID_TYPE_IRQ_EVENT 0x08
++
++/* Report type */
++#define GB_HID_INPUT_REPORT 0
++#define GB_HID_OUTPUT_REPORT 1
++#define GB_HID_FEATURE_REPORT 2
++
++/* Different request/response structures */
++/* HID get descriptor response */
++struct gb_hid_desc_response {
++ __u8 bLength;
++ __le16 wReportDescLength;
++ __le16 bcdHID;
++ __le16 wProductID;
++ __le16 wVendorID;
++ __u8 bCountryCode;
++} __packed;
++
++/* HID get report request/response */
++struct gb_hid_get_report_request {
++ __u8 report_type;
++ __u8 report_id;
++} __packed;
++
++/* HID set report request */
++struct gb_hid_set_report_request {
++ __u8 report_type;
++ __u8 report_id;
++ __u8 report[0];
++} __packed;
++
++/* HID input report request, via interrupt pipe */
++struct gb_hid_input_report_request {
++ __u8 report[0];
++} __packed;
++
++
++/* I2C */
++
++/* Greybus i2c request types */
++#define GB_I2C_TYPE_FUNCTIONALITY 0x02
++#define GB_I2C_TYPE_TRANSFER 0x05
++
++/* functionality request has no payload */
++struct gb_i2c_functionality_response {
++ __le32 functionality;
++} __packed;
++
++/*
++ * Outgoing data immediately follows the op count and ops array.
++ * The data for each write (master -> slave) op in the array is sent
++ * in order, with no (e.g. pad) bytes separating them.
++ *
++ * Short reads cause the entire transfer request to fail So response
++ * payload consists only of bytes read, and the number of bytes is
++ * exactly what was specified in the corresponding op. Like
++ * outgoing data, the incoming data is in order and contiguous.
++ */
++struct gb_i2c_transfer_op {
++ __le16 addr;
++ __le16 flags;
++ __le16 size;
++} __packed;
++
++struct gb_i2c_transfer_request {
++ __le16 op_count;
++ struct gb_i2c_transfer_op ops[0]; /* op_count of these */
++} __packed;
++struct gb_i2c_transfer_response {
++ __u8 data[0]; /* inbound data */
++} __packed;
++
++
++/* GPIO */
++
++/* Greybus GPIO request types */
++#define GB_GPIO_TYPE_LINE_COUNT 0x02
++#define GB_GPIO_TYPE_ACTIVATE 0x03
++#define GB_GPIO_TYPE_DEACTIVATE 0x04
++#define GB_GPIO_TYPE_GET_DIRECTION 0x05
++#define GB_GPIO_TYPE_DIRECTION_IN 0x06
++#define GB_GPIO_TYPE_DIRECTION_OUT 0x07
++#define GB_GPIO_TYPE_GET_VALUE 0x08
++#define GB_GPIO_TYPE_SET_VALUE 0x09
++#define GB_GPIO_TYPE_SET_DEBOUNCE 0x0a
++#define GB_GPIO_TYPE_IRQ_TYPE 0x0b
++#define GB_GPIO_TYPE_IRQ_MASK 0x0c
++#define GB_GPIO_TYPE_IRQ_UNMASK 0x0d
++#define GB_GPIO_TYPE_IRQ_EVENT 0x0e
++
++#define GB_GPIO_IRQ_TYPE_NONE 0x00
++#define GB_GPIO_IRQ_TYPE_EDGE_RISING 0x01
++#define GB_GPIO_IRQ_TYPE_EDGE_FALLING 0x02
++#define GB_GPIO_IRQ_TYPE_EDGE_BOTH 0x03
++#define GB_GPIO_IRQ_TYPE_LEVEL_HIGH 0x04
++#define GB_GPIO_IRQ_TYPE_LEVEL_LOW 0x08
++
++/* line count request has no payload */
++struct gb_gpio_line_count_response {
++ __u8 count;
++} __packed;
++
++struct gb_gpio_activate_request {
++ __u8 which;
++} __packed;
++/* activate response has no payload */
++
++struct gb_gpio_deactivate_request {
++ __u8 which;
++} __packed;
++/* deactivate response has no payload */
++
++struct gb_gpio_get_direction_request {
++ __u8 which;
++} __packed;
++struct gb_gpio_get_direction_response {
++ __u8 direction;
++} __packed;
++
++struct gb_gpio_direction_in_request {
++ __u8 which;
++} __packed;
++/* direction in response has no payload */
++
++struct gb_gpio_direction_out_request {
++ __u8 which;
++ __u8 value;
++} __packed;
++/* direction out response has no payload */
++
++struct gb_gpio_get_value_request {
++ __u8 which;
++} __packed;
++struct gb_gpio_get_value_response {
++ __u8 value;
++} __packed;
++
++struct gb_gpio_set_value_request {
++ __u8 which;
++ __u8 value;
++} __packed;
++/* set value response has no payload */
++
++struct gb_gpio_set_debounce_request {
++ __u8 which;
++ __le16 usec;
++} __packed;
++/* debounce response has no payload */
++
++struct gb_gpio_irq_type_request {
++ __u8 which;
++ __u8 type;
++} __packed;
++/* irq type response has no payload */
++
++struct gb_gpio_irq_mask_request {
++ __u8 which;
++} __packed;
++/* irq mask response has no payload */
++
++struct gb_gpio_irq_unmask_request {
++ __u8 which;
++} __packed;
++/* irq unmask response has no payload */
++
++/* irq event requests originate on another module and are handled on the AP */
++struct gb_gpio_irq_event_request {
++ __u8 which;
++} __packed;
++/* irq event has no response */
++
++
++/* PWM */
++
++/* Greybus PWM operation types */
++#define GB_PWM_TYPE_PWM_COUNT 0x02
++#define GB_PWM_TYPE_ACTIVATE 0x03
++#define GB_PWM_TYPE_DEACTIVATE 0x04
++#define GB_PWM_TYPE_CONFIG 0x05
++#define GB_PWM_TYPE_POLARITY 0x06
++#define GB_PWM_TYPE_ENABLE 0x07
++#define GB_PWM_TYPE_DISABLE 0x08
++
++/* pwm count request has no payload */
++struct gb_pwm_count_response {
++ __u8 count;
++} __packed;
++
++struct gb_pwm_activate_request {
++ __u8 which;
++} __packed;
++
++struct gb_pwm_deactivate_request {
++ __u8 which;
++} __packed;
++
++struct gb_pwm_config_request {
++ __u8 which;
++ __le32 duty;
++ __le32 period;
++} __packed;
++
++struct gb_pwm_polarity_request {
++ __u8 which;
++ __u8 polarity;
++} __packed;
++
++struct gb_pwm_enable_request {
++ __u8 which;
++} __packed;
++
++struct gb_pwm_disable_request {
++ __u8 which;
++} __packed;
++
++/* SPI */
++
++/* Should match up with modes in linux/spi/spi.h */
++#define GB_SPI_MODE_CPHA 0x01 /* clock phase */
++#define GB_SPI_MODE_CPOL 0x02 /* clock polarity */
++#define GB_SPI_MODE_MODE_0 (0|0) /* (original MicroWire) */
++#define GB_SPI_MODE_MODE_1 (0|GB_SPI_MODE_CPHA)
++#define GB_SPI_MODE_MODE_2 (GB_SPI_MODE_CPOL|0)
++#define GB_SPI_MODE_MODE_3 (GB_SPI_MODE_CPOL|GB_SPI_MODE_CPHA)
++#define GB_SPI_MODE_CS_HIGH 0x04 /* chipselect active high? */
++#define GB_SPI_MODE_LSB_FIRST 0x08 /* per-word bits-on-wire */
++#define GB_SPI_MODE_3WIRE 0x10 /* SI/SO signals shared */
++#define GB_SPI_MODE_LOOP 0x20 /* loopback mode */
++#define GB_SPI_MODE_NO_CS 0x40 /* 1 dev/bus, no chipselect */
++#define GB_SPI_MODE_READY 0x80 /* slave pulls low to pause */
++
++/* Should match up with flags in linux/spi/spi.h */
++#define GB_SPI_FLAG_HALF_DUPLEX BIT(0) /* can't do full duplex */
++#define GB_SPI_FLAG_NO_RX BIT(1) /* can't do buffer read */
++#define GB_SPI_FLAG_NO_TX BIT(2) /* can't do buffer write */
++
++/* Greybus spi operation types */
++#define GB_SPI_TYPE_MASTER_CONFIG 0x02
++#define GB_SPI_TYPE_DEVICE_CONFIG 0x03
++#define GB_SPI_TYPE_TRANSFER 0x04
++
++/* mode request has no payload */
++struct gb_spi_master_config_response {
++ __le32 bits_per_word_mask;
++ __le32 min_speed_hz;
++ __le32 max_speed_hz;
++ __le16 mode;
++ __le16 flags;
++ __u8 num_chipselect;
++} __packed;
++
++struct gb_spi_device_config_request {
++ __u8 chip_select;
++} __packed;
++
++struct gb_spi_device_config_response {
++ __le16 mode;
++ __u8 bits_per_word;
++ __le32 max_speed_hz;
++ __u8 device_type;
++#define GB_SPI_SPI_DEV 0x00
++#define GB_SPI_SPI_NOR 0x01
++#define GB_SPI_SPI_MODALIAS 0x02
++ __u8 name[32];
++} __packed;
++
++/**
++ * struct gb_spi_transfer - a read/write buffer pair
++ * @speed_hz: Select a speed other than the device default for this transfer. If
++ * 0 the default (from @spi_device) is used.
++ * @len: size of rx and tx buffers (in bytes)
++ * @delay_usecs: microseconds to delay after this transfer before (optionally)
++ * changing the chipselect status, then starting the next transfer or
++ * completing this spi_message.
++ * @cs_change: affects chipselect after this transfer completes
++ * @bits_per_word: select a bits_per_word other than the device default for this
++ * transfer. If 0 the default (from @spi_device) is used.
++ */
++struct gb_spi_transfer {
++ __le32 speed_hz;
++ __le32 len;
++ __le16 delay_usecs;
++ __u8 cs_change;
++ __u8 bits_per_word;
++ __u8 xfer_flags;
++#define GB_SPI_XFER_READ 0x01
++#define GB_SPI_XFER_WRITE 0x02
++#define GB_SPI_XFER_INPROGRESS 0x04
++} __packed;
++
++struct gb_spi_transfer_request {
++ __u8 chip_select; /* of the spi device */
++ __u8 mode; /* of the spi device */
++ __le16 count;
++ struct gb_spi_transfer transfers[0]; /* count of these */
++} __packed;
++
++struct gb_spi_transfer_response {
++ __u8 data[0]; /* inbound data */
++} __packed;
++
++/* Version of the Greybus SVC protocol we support */
++#define GB_SVC_VERSION_MAJOR 0x00
++#define GB_SVC_VERSION_MINOR 0x01
++
++/* Greybus SVC request types */
++#define GB_SVC_TYPE_PROTOCOL_VERSION 0x01
++#define GB_SVC_TYPE_SVC_HELLO 0x02
++#define GB_SVC_TYPE_INTF_DEVICE_ID 0x03
++#define GB_SVC_TYPE_INTF_RESET 0x06
++#define GB_SVC_TYPE_CONN_CREATE 0x07
++#define GB_SVC_TYPE_CONN_DESTROY 0x08
++#define GB_SVC_TYPE_DME_PEER_GET 0x09
++#define GB_SVC_TYPE_DME_PEER_SET 0x0a
++#define GB_SVC_TYPE_ROUTE_CREATE 0x0b
++#define GB_SVC_TYPE_ROUTE_DESTROY 0x0c
++#define GB_SVC_TYPE_TIMESYNC_ENABLE 0x0d
++#define GB_SVC_TYPE_TIMESYNC_DISABLE 0x0e
++#define GB_SVC_TYPE_TIMESYNC_AUTHORITATIVE 0x0f
++#define GB_SVC_TYPE_INTF_SET_PWRM 0x10
++#define GB_SVC_TYPE_INTF_EJECT 0x11
++#define GB_SVC_TYPE_PING 0x13
++#define GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET 0x14
++#define GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET 0x15
++#define GB_SVC_TYPE_PWRMON_SAMPLE_GET 0x16
++#define GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET 0x17
++#define GB_SVC_TYPE_TIMESYNC_WAKE_PINS_ACQUIRE 0x18
++#define GB_SVC_TYPE_TIMESYNC_WAKE_PINS_RELEASE 0x19
++#define GB_SVC_TYPE_TIMESYNC_PING 0x1a
++#define GB_SVC_TYPE_MODULE_INSERTED 0x1f
++#define GB_SVC_TYPE_MODULE_REMOVED 0x20
++#define GB_SVC_TYPE_INTF_VSYS_ENABLE 0x21
++#define GB_SVC_TYPE_INTF_VSYS_DISABLE 0x22
++#define GB_SVC_TYPE_INTF_REFCLK_ENABLE 0x23
++#define GB_SVC_TYPE_INTF_REFCLK_DISABLE 0x24
++#define GB_SVC_TYPE_INTF_UNIPRO_ENABLE 0x25
++#define GB_SVC_TYPE_INTF_UNIPRO_DISABLE 0x26
++#define GB_SVC_TYPE_INTF_ACTIVATE 0x27
++#define GB_SVC_TYPE_INTF_RESUME 0x28
++#define GB_SVC_TYPE_INTF_MAILBOX_EVENT 0x29
++#define GB_SVC_TYPE_INTF_OOPS 0x2a
++
++/* Greybus SVC protocol status values */
++#define GB_SVC_OP_SUCCESS 0x00
++#define GB_SVC_OP_UNKNOWN_ERROR 0x01
++#define GB_SVC_INTF_NOT_DETECTED 0x02
++#define GB_SVC_INTF_NO_UPRO_LINK 0x03
++#define GB_SVC_INTF_UPRO_NOT_DOWN 0x04
++#define GB_SVC_INTF_UPRO_NOT_HIBERNATED 0x05
++#define GB_SVC_INTF_NO_V_SYS 0x06
++#define GB_SVC_INTF_V_CHG 0x07
++#define GB_SVC_INTF_WAKE_BUSY 0x08
++#define GB_SVC_INTF_NO_REFCLK 0x09
++#define GB_SVC_INTF_RELEASING 0x0a
++#define GB_SVC_INTF_NO_ORDER 0x0b
++#define GB_SVC_INTF_MBOX_SET 0x0c
++#define GB_SVC_INTF_BAD_MBOX 0x0d
++#define GB_SVC_INTF_OP_TIMEOUT 0x0e
++#define GB_SVC_PWRMON_OP_NOT_PRESENT 0x0f
++
++struct gb_svc_version_request {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++struct gb_svc_version_response {
++ __u8 major;
++ __u8 minor;
++} __packed;
++
++/* SVC protocol hello request */
++struct gb_svc_hello_request {
++ __le16 endo_id;
++ __u8 interface_id;
++} __packed;
++/* hello response has no payload */
++
++struct gb_svc_intf_device_id_request {
++ __u8 intf_id;
++ __u8 device_id;
++} __packed;
++/* device id response has no payload */
++
++struct gb_svc_intf_reset_request {
++ __u8 intf_id;
++} __packed;
++/* interface reset response has no payload */
++
++struct gb_svc_intf_eject_request {
++ __u8 intf_id;
++} __packed;
++/* interface eject response has no payload */
++
++struct gb_svc_conn_create_request {
++ __u8 intf1_id;
++ __le16 cport1_id;
++ __u8 intf2_id;
++ __le16 cport2_id;
++ __u8 tc;
++ __u8 flags;
++} __packed;
++/* connection create response has no payload */
++
++struct gb_svc_conn_destroy_request {
++ __u8 intf1_id;
++ __le16 cport1_id;
++ __u8 intf2_id;
++ __le16 cport2_id;
++} __packed;
++/* connection destroy response has no payload */
++
++struct gb_svc_dme_peer_get_request {
++ __u8 intf_id;
++ __le16 attr;
++ __le16 selector;
++} __packed;
++
++struct gb_svc_dme_peer_get_response {
++ __le16 result_code;
++ __le32 attr_value;
++} __packed;
++
++struct gb_svc_dme_peer_set_request {
++ __u8 intf_id;
++ __le16 attr;
++ __le16 selector;
++ __le32 value;
++} __packed;
++
++struct gb_svc_dme_peer_set_response {
++ __le16 result_code;
++} __packed;
++
++/* Greybus init-status values, currently retrieved using DME peer gets. */
++#define GB_INIT_SPI_BOOT_STARTED 0x02
++#define GB_INIT_TRUSTED_SPI_BOOT_FINISHED 0x03
++#define GB_INIT_UNTRUSTED_SPI_BOOT_FINISHED 0x04
++#define GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED 0x06
++#define GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED 0x09
++#define GB_INIT_S2_LOADER_BOOT_STARTED 0x0D
++
++struct gb_svc_route_create_request {
++ __u8 intf1_id;
++ __u8 dev1_id;
++ __u8 intf2_id;
++ __u8 dev2_id;
++} __packed;
++/* route create response has no payload */
++
++struct gb_svc_route_destroy_request {
++ __u8 intf1_id;
++ __u8 intf2_id;
++} __packed;
++/* route destroy response has no payload */
++
++/* used for svc_intf_vsys_{enable,disable} */
++struct gb_svc_intf_vsys_request {
++ __u8 intf_id;
++} __packed;
++
++struct gb_svc_intf_vsys_response {
++ __u8 result_code;
++#define GB_SVC_INTF_VSYS_OK 0x00
++ /* 0x01 is reserved */
++#define GB_SVC_INTF_VSYS_FAIL 0x02
++} __packed;
++
++/* used for svc_intf_refclk_{enable,disable} */
++struct gb_svc_intf_refclk_request {
++ __u8 intf_id;
++} __packed;
++
++struct gb_svc_intf_refclk_response {
++ __u8 result_code;
++#define GB_SVC_INTF_REFCLK_OK 0x00
++ /* 0x01 is reserved */
++#define GB_SVC_INTF_REFCLK_FAIL 0x02
++} __packed;
++
++/* used for svc_intf_unipro_{enable,disable} */
++struct gb_svc_intf_unipro_request {
++ __u8 intf_id;
++} __packed;
++
++struct gb_svc_intf_unipro_response {
++ __u8 result_code;
++#define GB_SVC_INTF_UNIPRO_OK 0x00
++ /* 0x01 is reserved */
++#define GB_SVC_INTF_UNIPRO_FAIL 0x02
++#define GB_SVC_INTF_UNIPRO_NOT_OFF 0x03
++} __packed;
++
++struct gb_svc_timesync_enable_request {
++ __u8 count;
++ __le64 frame_time;
++ __le32 strobe_delay;
++ __le32 refclk;
++} __packed;
++/* timesync enable response has no payload */
++
++/* timesync authoritative request has no payload */
++struct gb_svc_timesync_authoritative_response {
++ __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
++};
++
++struct gb_svc_timesync_wake_pins_acquire_request {
++ __le32 strobe_mask;
++};
++
++/* timesync wake pins acquire response has no payload */
++
++/* timesync wake pins release request has no payload */
++/* timesync wake pins release response has no payload */
++
++/* timesync svc ping request has no payload */
++struct gb_svc_timesync_ping_response {
++ __le64 frame_time;
++} __packed;
++
++#define GB_SVC_UNIPRO_FAST_MODE 0x01
++#define GB_SVC_UNIPRO_SLOW_MODE 0x02
++#define GB_SVC_UNIPRO_FAST_AUTO_MODE 0x04
++#define GB_SVC_UNIPRO_SLOW_AUTO_MODE 0x05
++#define GB_SVC_UNIPRO_MODE_UNCHANGED 0x07
++#define GB_SVC_UNIPRO_HIBERNATE_MODE 0x11
++#define GB_SVC_UNIPRO_OFF_MODE 0x12
++
++#define GB_SVC_SMALL_AMPLITUDE 0x01
++#define GB_SVC_LARGE_AMPLITUDE 0x02
++
++#define GB_SVC_NO_DE_EMPHASIS 0x00
++#define GB_SVC_SMALL_DE_EMPHASIS 0x01
++#define GB_SVC_LARGE_DE_EMPHASIS 0x02
++
++#define GB_SVC_PWRM_RXTERMINATION 0x01
++#define GB_SVC_PWRM_TXTERMINATION 0x02
++#define GB_SVC_PWRM_LINE_RESET 0x04
++#define GB_SVC_PWRM_SCRAMBLING 0x20
++
++#define GB_SVC_PWRM_QUIRK_HSSER 0x00000001
++
++#define GB_SVC_UNIPRO_HS_SERIES_A 0x01
++#define GB_SVC_UNIPRO_HS_SERIES_B 0x02
++
++#define GB_SVC_SETPWRM_PWR_OK 0x00
++#define GB_SVC_SETPWRM_PWR_LOCAL 0x01
++#define GB_SVC_SETPWRM_PWR_REMOTE 0x02
++#define GB_SVC_SETPWRM_PWR_BUSY 0x03
++#define GB_SVC_SETPWRM_PWR_ERROR_CAP 0x04
++#define GB_SVC_SETPWRM_PWR_FATAL_ERROR 0x05
++
++struct gb_svc_l2_timer_cfg {
++ __le16 tsb_fc0_protection_timeout;
++ __le16 tsb_tc0_replay_timeout;
++ __le16 tsb_afc0_req_timeout;
++ __le16 tsb_fc1_protection_timeout;
++ __le16 tsb_tc1_replay_timeout;
++ __le16 tsb_afc1_req_timeout;
++ __le16 reserved_for_tc2[3];
++ __le16 reserved_for_tc3[3];
++} __packed;
++
++struct gb_svc_intf_set_pwrm_request {
++ __u8 intf_id;
++ __u8 hs_series;
++ __u8 tx_mode;
++ __u8 tx_gear;
++ __u8 tx_nlanes;
++ __u8 tx_amplitude;
++ __u8 tx_hs_equalizer;
++ __u8 rx_mode;
++ __u8 rx_gear;
++ __u8 rx_nlanes;
++ __u8 flags;
++ __le32 quirks;
++ struct gb_svc_l2_timer_cfg local_l2timerdata, remote_l2timerdata;
++} __packed;
++
++struct gb_svc_intf_set_pwrm_response {
++ __u8 result_code;
++} __packed;
++
++struct gb_svc_key_event_request {
++ __le16 key_code;
++#define GB_KEYCODE_ARA 0x00
++
++ __u8 key_event;
++#define GB_SVC_KEY_RELEASED 0x00
++#define GB_SVC_KEY_PRESSED 0x01
++} __packed;
++
++#define GB_SVC_PWRMON_MAX_RAIL_COUNT 254
++
++struct gb_svc_pwrmon_rail_count_get_response {
++ __u8 rail_count;
++} __packed;
++
++#define GB_SVC_PWRMON_RAIL_NAME_BUFSIZE 32
++
++struct gb_svc_pwrmon_rail_names_get_response {
++ __u8 status;
++ __u8 name[0][GB_SVC_PWRMON_RAIL_NAME_BUFSIZE];
++} __packed;
++
++#define GB_SVC_PWRMON_TYPE_CURR 0x01
++#define GB_SVC_PWRMON_TYPE_VOL 0x02
++#define GB_SVC_PWRMON_TYPE_PWR 0x03
++
++#define GB_SVC_PWRMON_GET_SAMPLE_OK 0x00
++#define GB_SVC_PWRMON_GET_SAMPLE_INVAL 0x01
++#define GB_SVC_PWRMON_GET_SAMPLE_NOSUPP 0x02
++#define GB_SVC_PWRMON_GET_SAMPLE_HWERR 0x03
++
++struct gb_svc_pwrmon_sample_get_request {
++ __u8 rail_id;
++ __u8 measurement_type;
++} __packed;
++
++struct gb_svc_pwrmon_sample_get_response {
++ __u8 result;
++ __le32 measurement;
++} __packed;
++
++struct gb_svc_pwrmon_intf_sample_get_request {
++ __u8 intf_id;
++ __u8 measurement_type;
++} __packed;
++
++struct gb_svc_pwrmon_intf_sample_get_response {
++ __u8 result;
++ __le32 measurement;
++} __packed;
++
++#define GB_SVC_MODULE_INSERTED_FLAG_NO_PRIMARY 0x0001
++
++struct gb_svc_module_inserted_request {
++ __u8 primary_intf_id;
++ __u8 intf_count;
++ __le16 flags;
++} __packed;
++/* module_inserted response has no payload */
++
++struct gb_svc_module_removed_request {
++ __u8 primary_intf_id;
++} __packed;
++/* module_removed response has no payload */
++
++struct gb_svc_intf_activate_request {
++ __u8 intf_id;
++} __packed;
++
++#define GB_SVC_INTF_TYPE_UNKNOWN 0x00
++#define GB_SVC_INTF_TYPE_DUMMY 0x01
++#define GB_SVC_INTF_TYPE_UNIPRO 0x02
++#define GB_SVC_INTF_TYPE_GREYBUS 0x03
++
++struct gb_svc_intf_activate_response {
++ __u8 status;
++ __u8 intf_type;
++} __packed;
++
++struct gb_svc_intf_resume_request {
++ __u8 intf_id;
++} __packed;
++
++struct gb_svc_intf_resume_response {
++ __u8 status;
++} __packed;
++
++#define GB_SVC_INTF_MAILBOX_NONE 0x00
++#define GB_SVC_INTF_MAILBOX_AP 0x01
++#define GB_SVC_INTF_MAILBOX_GREYBUS 0x02
++
++struct gb_svc_intf_mailbox_event_request {
++ __u8 intf_id;
++ __le16 result_code;
++ __le32 mailbox;
++} __packed;
++/* intf_mailbox_event response has no payload */
++
++struct gb_svc_intf_oops_request {
++ __u8 intf_id;
++ __u8 reason;
++} __packed;
++/* intf_oops response has no payload */
++
++
++/* RAW */
++
++/* Greybus raw request types */
++#define GB_RAW_TYPE_SEND 0x02
++
++struct gb_raw_send_request {
++ __le32 len;
++ __u8 data[0];
++} __packed;
++
++
++/* UART */
++
++/* Greybus UART operation types */
++#define GB_UART_TYPE_SEND_DATA 0x02
++#define GB_UART_TYPE_RECEIVE_DATA 0x03 /* Unsolicited data */
++#define GB_UART_TYPE_SET_LINE_CODING 0x04
++#define GB_UART_TYPE_SET_CONTROL_LINE_STATE 0x05
++#define GB_UART_TYPE_SEND_BREAK 0x06
++#define GB_UART_TYPE_SERIAL_STATE 0x07 /* Unsolicited data */
++#define GB_UART_TYPE_RECEIVE_CREDITS 0x08
++#define GB_UART_TYPE_FLUSH_FIFOS 0x09
++
++/* Represents data from AP -> Module */
++struct gb_uart_send_data_request {
++ __le16 size;
++ __u8 data[0];
++} __packed;
++
++/* recv-data-request flags */
++#define GB_UART_RECV_FLAG_FRAMING 0x01 /* Framing error */
++#define GB_UART_RECV_FLAG_PARITY 0x02 /* Parity error */
++#define GB_UART_RECV_FLAG_OVERRUN 0x04 /* Overrun error */
++#define GB_UART_RECV_FLAG_BREAK 0x08 /* Break */
++
++/* Represents data from Module -> AP */
++struct gb_uart_recv_data_request {
++ __le16 size;
++ __u8 flags;
++ __u8 data[0];
++} __packed;
++
++struct gb_uart_receive_credits_request {
++ __le16 count;
++} __packed;
++
++struct gb_uart_set_line_coding_request {
++ __le32 rate;
++ __u8 format;
++#define GB_SERIAL_1_STOP_BITS 0
++#define GB_SERIAL_1_5_STOP_BITS 1
++#define GB_SERIAL_2_STOP_BITS 2
++
++ __u8 parity;
++#define GB_SERIAL_NO_PARITY 0
++#define GB_SERIAL_ODD_PARITY 1
++#define GB_SERIAL_EVEN_PARITY 2
++#define GB_SERIAL_MARK_PARITY 3
++#define GB_SERIAL_SPACE_PARITY 4
++
++ __u8 data_bits;
++
++ __u8 flow_control;
++#define GB_SERIAL_AUTO_RTSCTS_EN 0x1
++} __packed;
++
++/* output control lines */
++#define GB_UART_CTRL_DTR 0x01
++#define GB_UART_CTRL_RTS 0x02
++
++struct gb_uart_set_control_line_state_request {
++ __u8 control;
++} __packed;
++
++struct gb_uart_set_break_request {
++ __u8 state;
++} __packed;
++
++/* input control lines and line errors */
++#define GB_UART_CTRL_DCD 0x01
++#define GB_UART_CTRL_DSR 0x02
++#define GB_UART_CTRL_RI 0x04
++
++struct gb_uart_serial_state_request {
++ __u8 control;
++} __packed;
++
++struct gb_uart_serial_flush_request {
++ __u8 flags;
++#define GB_SERIAL_FLAG_FLUSH_TRANSMITTER 0x01
++#define GB_SERIAL_FLAG_FLUSH_RECEIVER 0x02
++} __packed;
++
++/* Loopback */
++
++/* Greybus loopback request types */
++#define GB_LOOPBACK_TYPE_PING 0x02
++#define GB_LOOPBACK_TYPE_TRANSFER 0x03
++#define GB_LOOPBACK_TYPE_SINK 0x04
++
++/*
++ * Loopback request/response header format should be identical
++ * to simplify bandwidth and data movement analysis.
++ */
++struct gb_loopback_transfer_request {
++ __le32 len;
++ __le32 reserved0;
++ __le32 reserved1;
++ __u8 data[0];
++} __packed;
++
++struct gb_loopback_transfer_response {
++ __le32 len;
++ __le32 reserved0;
++ __le32 reserved1;
++ __u8 data[0];
++} __packed;
++
++/* SDIO */
++/* Greybus SDIO operation types */
++#define GB_SDIO_TYPE_GET_CAPABILITIES 0x02
++#define GB_SDIO_TYPE_SET_IOS 0x03
++#define GB_SDIO_TYPE_COMMAND 0x04
++#define GB_SDIO_TYPE_TRANSFER 0x05
++#define GB_SDIO_TYPE_EVENT 0x06
++
++/* get caps response: request has no payload */
++struct gb_sdio_get_caps_response {
++ __le32 caps;
++#define GB_SDIO_CAP_NONREMOVABLE 0x00000001
++#define GB_SDIO_CAP_4_BIT_DATA 0x00000002
++#define GB_SDIO_CAP_8_BIT_DATA 0x00000004
++#define GB_SDIO_CAP_MMC_HS 0x00000008
++#define GB_SDIO_CAP_SD_HS 0x00000010
++#define GB_SDIO_CAP_ERASE 0x00000020
++#define GB_SDIO_CAP_1_2V_DDR 0x00000040
++#define GB_SDIO_CAP_1_8V_DDR 0x00000080
++#define GB_SDIO_CAP_POWER_OFF_CARD 0x00000100
++#define GB_SDIO_CAP_UHS_SDR12 0x00000200
++#define GB_SDIO_CAP_UHS_SDR25 0x00000400
++#define GB_SDIO_CAP_UHS_SDR50 0x00000800
++#define GB_SDIO_CAP_UHS_SDR104 0x00001000
++#define GB_SDIO_CAP_UHS_DDR50 0x00002000
++#define GB_SDIO_CAP_DRIVER_TYPE_A 0x00004000
++#define GB_SDIO_CAP_DRIVER_TYPE_C 0x00008000
++#define GB_SDIO_CAP_DRIVER_TYPE_D 0x00010000
++#define GB_SDIO_CAP_HS200_1_2V 0x00020000
++#define GB_SDIO_CAP_HS200_1_8V 0x00040000
++#define GB_SDIO_CAP_HS400_1_2V 0x00080000
++#define GB_SDIO_CAP_HS400_1_8V 0x00100000
++
++ /* see possible values below at vdd */
++ __le32 ocr;
++ __le32 f_min;
++ __le32 f_max;
++ __le16 max_blk_count;
++ __le16 max_blk_size;
++} __packed;
++
++/* set ios request: response has no payload */
++struct gb_sdio_set_ios_request {
++ __le32 clock;
++ __le32 vdd;
++#define GB_SDIO_VDD_165_195 0x00000001
++#define GB_SDIO_VDD_20_21 0x00000002
++#define GB_SDIO_VDD_21_22 0x00000004
++#define GB_SDIO_VDD_22_23 0x00000008
++#define GB_SDIO_VDD_23_24 0x00000010
++#define GB_SDIO_VDD_24_25 0x00000020
++#define GB_SDIO_VDD_25_26 0x00000040
++#define GB_SDIO_VDD_26_27 0x00000080
++#define GB_SDIO_VDD_27_28 0x00000100
++#define GB_SDIO_VDD_28_29 0x00000200
++#define GB_SDIO_VDD_29_30 0x00000400
++#define GB_SDIO_VDD_30_31 0x00000800
++#define GB_SDIO_VDD_31_32 0x00001000
++#define GB_SDIO_VDD_32_33 0x00002000
++#define GB_SDIO_VDD_33_34 0x00004000
++#define GB_SDIO_VDD_34_35 0x00008000
++#define GB_SDIO_VDD_35_36 0x00010000
++
++ __u8 bus_mode;
++#define GB_SDIO_BUSMODE_OPENDRAIN 0x00
++#define GB_SDIO_BUSMODE_PUSHPULL 0x01
++
++ __u8 power_mode;
++#define GB_SDIO_POWER_OFF 0x00
++#define GB_SDIO_POWER_UP 0x01
++#define GB_SDIO_POWER_ON 0x02
++#define GB_SDIO_POWER_UNDEFINED 0x03
++
++ __u8 bus_width;
++#define GB_SDIO_BUS_WIDTH_1 0x00
++#define GB_SDIO_BUS_WIDTH_4 0x02
++#define GB_SDIO_BUS_WIDTH_8 0x03
++
++ __u8 timing;
++#define GB_SDIO_TIMING_LEGACY 0x00
++#define GB_SDIO_TIMING_MMC_HS 0x01
++#define GB_SDIO_TIMING_SD_HS 0x02
++#define GB_SDIO_TIMING_UHS_SDR12 0x03
++#define GB_SDIO_TIMING_UHS_SDR25 0x04
++#define GB_SDIO_TIMING_UHS_SDR50 0x05
++#define GB_SDIO_TIMING_UHS_SDR104 0x06
++#define GB_SDIO_TIMING_UHS_DDR50 0x07
++#define GB_SDIO_TIMING_MMC_DDR52 0x08
++#define GB_SDIO_TIMING_MMC_HS200 0x09
++#define GB_SDIO_TIMING_MMC_HS400 0x0A
++
++ __u8 signal_voltage;
++#define GB_SDIO_SIGNAL_VOLTAGE_330 0x00
++#define GB_SDIO_SIGNAL_VOLTAGE_180 0x01
++#define GB_SDIO_SIGNAL_VOLTAGE_120 0x02
++
++ __u8 drv_type;
++#define GB_SDIO_SET_DRIVER_TYPE_B 0x00
++#define GB_SDIO_SET_DRIVER_TYPE_A 0x01
++#define GB_SDIO_SET_DRIVER_TYPE_C 0x02
++#define GB_SDIO_SET_DRIVER_TYPE_D 0x03
++} __packed;
++
++/* command request */
++struct gb_sdio_command_request {
++ __u8 cmd;
++ __u8 cmd_flags;
++#define GB_SDIO_RSP_NONE 0x00
++#define GB_SDIO_RSP_PRESENT 0x01
++#define GB_SDIO_RSP_136 0x02
++#define GB_SDIO_RSP_CRC 0x04
++#define GB_SDIO_RSP_BUSY 0x08
++#define GB_SDIO_RSP_OPCODE 0x10
++
++ __u8 cmd_type;
++#define GB_SDIO_CMD_AC 0x00
++#define GB_SDIO_CMD_ADTC 0x01
++#define GB_SDIO_CMD_BC 0x02
++#define GB_SDIO_CMD_BCR 0x03
++
++ __le32 cmd_arg;
++ __le16 data_blocks;
++ __le16 data_blksz;
++} __packed;
++
++struct gb_sdio_command_response {
++ __le32 resp[4];
++} __packed;
++
++/* transfer request */
++struct gb_sdio_transfer_request {
++ __u8 data_flags;
++#define GB_SDIO_DATA_WRITE 0x01
++#define GB_SDIO_DATA_READ 0x02
++#define GB_SDIO_DATA_STREAM 0x04
++
++ __le16 data_blocks;
++ __le16 data_blksz;
++ __u8 data[0];
++} __packed;
++
++struct gb_sdio_transfer_response {
++ __le16 data_blocks;
++ __le16 data_blksz;
++ __u8 data[0];
++} __packed;
++
++/* event request: generated by module and is defined as unidirectional */
++struct gb_sdio_event_request {
++ __u8 event;
++#define GB_SDIO_CARD_INSERTED 0x01
++#define GB_SDIO_CARD_REMOVED 0x02
++#define GB_SDIO_WP 0x04
++} __packed;
++
++/* Camera */
++
++/* Greybus Camera request types */
++#define GB_CAMERA_TYPE_CAPABILITIES 0x02
++#define GB_CAMERA_TYPE_CONFIGURE_STREAMS 0x03
++#define GB_CAMERA_TYPE_CAPTURE 0x04
++#define GB_CAMERA_TYPE_FLUSH 0x05
++#define GB_CAMERA_TYPE_METADATA 0x06
++
++#define GB_CAMERA_MAX_STREAMS 4
++#define GB_CAMERA_MAX_SETTINGS_SIZE 8192
++
++/* Greybus Camera Configure Streams request payload */
++struct gb_camera_stream_config_request {
++ __le16 width;
++ __le16 height;
++ __le16 format;
++ __le16 padding;
++} __packed;
++
++struct gb_camera_configure_streams_request {
++ __u8 num_streams;
++ __u8 flags;
++#define GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY 0x01
++ __le16 padding;
++ struct gb_camera_stream_config_request config[0];
++} __packed;
++
++/* Greybus Camera Configure Streams response payload */
++struct gb_camera_stream_config_response {
++ __le16 width;
++ __le16 height;
++ __le16 format;
++ __u8 virtual_channel;
++ __u8 data_type[2];
++ __le16 max_pkt_size;
++ __u8 padding;
++ __le32 max_size;
++} __packed;
++
++struct gb_camera_configure_streams_response {
++ __u8 num_streams;
++#define GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED 0x01
++ __u8 flags;
++ __u8 padding[2];
++ __le32 data_rate;
++ struct gb_camera_stream_config_response config[0];
++};
++
++/* Greybus Camera Capture request payload - response has no payload */
++struct gb_camera_capture_request {
++ __le32 request_id;
++ __u8 streams;
++ __u8 padding;
++ __le16 num_frames;
++ __u8 settings[0];
++} __packed;
++
++/* Greybus Camera Flush response payload - request has no payload */
++struct gb_camera_flush_response {
++ __le32 request_id;
++} __packed;
++
++/* Greybus Camera Metadata request payload - operation has no response */
++struct gb_camera_metadata_request {
++ __le32 request_id;
++ __le16 frame_number;
++ __u8 stream;
++ __u8 padding;
++ __u8 metadata[0];
++} __packed;
++
++/* Lights */
++
++/* Greybus Lights request types */
++#define GB_LIGHTS_TYPE_GET_LIGHTS 0x02
++#define GB_LIGHTS_TYPE_GET_LIGHT_CONFIG 0x03
++#define GB_LIGHTS_TYPE_GET_CHANNEL_CONFIG 0x04
++#define GB_LIGHTS_TYPE_GET_CHANNEL_FLASH_CONFIG 0x05
++#define GB_LIGHTS_TYPE_SET_BRIGHTNESS 0x06
++#define GB_LIGHTS_TYPE_SET_BLINK 0x07
++#define GB_LIGHTS_TYPE_SET_COLOR 0x08
++#define GB_LIGHTS_TYPE_SET_FADE 0x09
++#define GB_LIGHTS_TYPE_EVENT 0x0A
++#define GB_LIGHTS_TYPE_SET_FLASH_INTENSITY 0x0B
++#define GB_LIGHTS_TYPE_SET_FLASH_STROBE 0x0C
++#define GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT 0x0D
++#define GB_LIGHTS_TYPE_GET_FLASH_FAULT 0x0E
++
++/* Greybus Light modes */
++
++/*
++ * if you add any specific mode below, update also the
++ * GB_CHANNEL_MODE_DEFINED_RANGE value accordingly
++ */
++#define GB_CHANNEL_MODE_NONE 0x00000000
++#define GB_CHANNEL_MODE_BATTERY 0x00000001
++#define GB_CHANNEL_MODE_POWER 0x00000002
++#define GB_CHANNEL_MODE_WIRELESS 0x00000004
++#define GB_CHANNEL_MODE_BLUETOOTH 0x00000008
++#define GB_CHANNEL_MODE_KEYBOARD 0x00000010
++#define GB_CHANNEL_MODE_BUTTONS 0x00000020
++#define GB_CHANNEL_MODE_NOTIFICATION 0x00000040
++#define GB_CHANNEL_MODE_ATTENTION 0x00000080
++#define GB_CHANNEL_MODE_FLASH 0x00000100
++#define GB_CHANNEL_MODE_TORCH 0x00000200
++#define GB_CHANNEL_MODE_INDICATOR 0x00000400
++
++/* Lights Mode valid bit values */
++#define GB_CHANNEL_MODE_DEFINED_RANGE 0x000004FF
++#define GB_CHANNEL_MODE_VENDOR_RANGE 0x00F00000
++
++/* Greybus Light Channels Flags */
++#define GB_LIGHT_CHANNEL_MULTICOLOR 0x00000001
++#define GB_LIGHT_CHANNEL_FADER 0x00000002
++#define GB_LIGHT_CHANNEL_BLINK 0x00000004
++
++/* get count of lights in module */
++struct gb_lights_get_lights_response {
++ __u8 lights_count;
++} __packed;
++
++/* light config request payload */
++struct gb_lights_get_light_config_request {
++ __u8 id;
++} __packed;
++
++/* light config response payload */
++struct gb_lights_get_light_config_response {
++ __u8 channel_count;
++ __u8 name[32];
++} __packed;
++
++/* channel config request payload */
++struct gb_lights_get_channel_config_request {
++ __u8 light_id;
++ __u8 channel_id;
++} __packed;
++
++/* channel flash config request payload */
++struct gb_lights_get_channel_flash_config_request {
++ __u8 light_id;
++ __u8 channel_id;
++} __packed;
++
++/* channel config response payload */
++struct gb_lights_get_channel_config_response {
++ __u8 max_brightness;
++ __le32 flags;
++ __le32 color;
++ __u8 color_name[32];
++ __le32 mode;
++ __u8 mode_name[32];
++} __packed;
++
++/* channel flash config response payload */
++struct gb_lights_get_channel_flash_config_response {
++ __le32 intensity_min_uA;
++ __le32 intensity_max_uA;
++ __le32 intensity_step_uA;
++ __le32 timeout_min_us;
++ __le32 timeout_max_us;
++ __le32 timeout_step_us;
++} __packed;
++
++/* blink request payload: response have no payload */
++struct gb_lights_blink_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __le16 time_on_ms;
++ __le16 time_off_ms;
++} __packed;
++
++/* set brightness request payload: response have no payload */
++struct gb_lights_set_brightness_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __u8 brightness;
++} __packed;
++
++/* set color request payload: response have no payload */
++struct gb_lights_set_color_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __le32 color;
++} __packed;
++
++/* set fade request payload: response have no payload */
++struct gb_lights_set_fade_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __u8 fade_in;
++ __u8 fade_out;
++} __packed;
++
++/* event request: generated by module */
++struct gb_lights_event_request {
++ __u8 light_id;
++ __u8 event;
++#define GB_LIGHTS_LIGHT_CONFIG 0x01
++} __packed;
++
++/* set flash intensity request payload: response have no payload */
++struct gb_lights_set_flash_intensity_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __le32 intensity_uA;
++} __packed;
++
++/* set flash strobe state request payload: response have no payload */
++struct gb_lights_set_flash_strobe_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __u8 state;
++} __packed;
++
++/* set flash timeout request payload: response have no payload */
++struct gb_lights_set_flash_timeout_request {
++ __u8 light_id;
++ __u8 channel_id;
++ __le32 timeout_us;
++} __packed;
++
++/* get flash fault request payload */
++struct gb_lights_get_flash_fault_request {
++ __u8 light_id;
++ __u8 channel_id;
++} __packed;
++
++/* get flash fault response payload */
++struct gb_lights_get_flash_fault_response {
++ __le32 fault;
++#define GB_LIGHTS_FLASH_FAULT_OVER_VOLTAGE 0x00000000
++#define GB_LIGHTS_FLASH_FAULT_TIMEOUT 0x00000001
++#define GB_LIGHTS_FLASH_FAULT_OVER_TEMPERATURE 0x00000002
++#define GB_LIGHTS_FLASH_FAULT_SHORT_CIRCUIT 0x00000004
++#define GB_LIGHTS_FLASH_FAULT_OVER_CURRENT 0x00000008
++#define GB_LIGHTS_FLASH_FAULT_INDICATOR 0x00000010
++#define GB_LIGHTS_FLASH_FAULT_UNDER_VOLTAGE 0x00000020
++#define GB_LIGHTS_FLASH_FAULT_INPUT_VOLTAGE 0x00000040
++#define GB_LIGHTS_FLASH_FAULT_LED_OVER_TEMPERATURE 0x00000080
++} __packed;
++
++/* Audio */
++
++#define GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE 0x02
++#define GB_AUDIO_TYPE_GET_TOPOLOGY 0x03
++#define GB_AUDIO_TYPE_GET_CONTROL 0x04
++#define GB_AUDIO_TYPE_SET_CONTROL 0x05
++#define GB_AUDIO_TYPE_ENABLE_WIDGET 0x06
++#define GB_AUDIO_TYPE_DISABLE_WIDGET 0x07
++#define GB_AUDIO_TYPE_GET_PCM 0x08
++#define GB_AUDIO_TYPE_SET_PCM 0x09
++#define GB_AUDIO_TYPE_SET_TX_DATA_SIZE 0x0a
++ /* 0x0b unused */
++#define GB_AUDIO_TYPE_ACTIVATE_TX 0x0c
++#define GB_AUDIO_TYPE_DEACTIVATE_TX 0x0d
++#define GB_AUDIO_TYPE_SET_RX_DATA_SIZE 0x0e
++ /* 0x0f unused */
++#define GB_AUDIO_TYPE_ACTIVATE_RX 0x10
++#define GB_AUDIO_TYPE_DEACTIVATE_RX 0x11
++#define GB_AUDIO_TYPE_JACK_EVENT 0x12
++#define GB_AUDIO_TYPE_BUTTON_EVENT 0x13
++#define GB_AUDIO_TYPE_STREAMING_EVENT 0x14
++#define GB_AUDIO_TYPE_SEND_DATA 0x15
++
++/* Module must be able to buffer 10ms of audio data, minimum */
++#define GB_AUDIO_SAMPLE_BUFFER_MIN_US 10000
++
++#define GB_AUDIO_PCM_NAME_MAX 32
++#define AUDIO_DAI_NAME_MAX 32
++#define AUDIO_CONTROL_NAME_MAX 32
++#define AUDIO_CTL_ELEM_NAME_MAX 44
++#define AUDIO_ENUM_NAME_MAX 64
++#define AUDIO_WIDGET_NAME_MAX 32
++
++/* See SNDRV_PCM_FMTBIT_* in Linux source */
++#define GB_AUDIO_PCM_FMT_S8 BIT(0)
++#define GB_AUDIO_PCM_FMT_U8 BIT(1)
++#define GB_AUDIO_PCM_FMT_S16_LE BIT(2)
++#define GB_AUDIO_PCM_FMT_S16_BE BIT(3)
++#define GB_AUDIO_PCM_FMT_U16_LE BIT(4)
++#define GB_AUDIO_PCM_FMT_U16_BE BIT(5)
++#define GB_AUDIO_PCM_FMT_S24_LE BIT(6)
++#define GB_AUDIO_PCM_FMT_S24_BE BIT(7)
++#define GB_AUDIO_PCM_FMT_U24_LE BIT(8)
++#define GB_AUDIO_PCM_FMT_U24_BE BIT(9)
++#define GB_AUDIO_PCM_FMT_S32_LE BIT(10)
++#define GB_AUDIO_PCM_FMT_S32_BE BIT(11)
++#define GB_AUDIO_PCM_FMT_U32_LE BIT(12)
++#define GB_AUDIO_PCM_FMT_U32_BE BIT(13)
++
++/* See SNDRV_PCM_RATE_* in Linux source */
++#define GB_AUDIO_PCM_RATE_5512 BIT(0)
++#define GB_AUDIO_PCM_RATE_8000 BIT(1)
++#define GB_AUDIO_PCM_RATE_11025 BIT(2)
++#define GB_AUDIO_PCM_RATE_16000 BIT(3)
++#define GB_AUDIO_PCM_RATE_22050 BIT(4)
++#define GB_AUDIO_PCM_RATE_32000 BIT(5)
++#define GB_AUDIO_PCM_RATE_44100 BIT(6)
++#define GB_AUDIO_PCM_RATE_48000 BIT(7)
++#define GB_AUDIO_PCM_RATE_64000 BIT(8)
++#define GB_AUDIO_PCM_RATE_88200 BIT(9)
++#define GB_AUDIO_PCM_RATE_96000 BIT(10)
++#define GB_AUDIO_PCM_RATE_176400 BIT(11)
++#define GB_AUDIO_PCM_RATE_192000 BIT(12)
++
++#define GB_AUDIO_STREAM_TYPE_CAPTURE 0x1
++#define GB_AUDIO_STREAM_TYPE_PLAYBACK 0x2
++
++#define GB_AUDIO_CTL_ELEM_ACCESS_READ BIT(0)
++#define GB_AUDIO_CTL_ELEM_ACCESS_WRITE BIT(1)
++
++/* See SNDRV_CTL_ELEM_TYPE_* in Linux source */
++#define GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN 0x01
++#define GB_AUDIO_CTL_ELEM_TYPE_INTEGER 0x02
++#define GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED 0x03
++#define GB_AUDIO_CTL_ELEM_TYPE_INTEGER64 0x06
++
++/* See SNDRV_CTL_ELEM_IFACE_* in Linux source */
++#define GB_AUDIO_CTL_ELEM_IFACE_CARD 0x00
++#define GB_AUDIO_CTL_ELEM_IFACE_HWDEP 0x01
++#define GB_AUDIO_CTL_ELEM_IFACE_MIXER 0x02
++#define GB_AUDIO_CTL_ELEM_IFACE_PCM 0x03
++#define GB_AUDIO_CTL_ELEM_IFACE_RAWMIDI 0x04
++#define GB_AUDIO_CTL_ELEM_IFACE_TIMER 0x05
++#define GB_AUDIO_CTL_ELEM_IFACE_SEQUENCER 0x06
++
++/* SNDRV_CTL_ELEM_ACCESS_* in Linux source */
++#define GB_AUDIO_ACCESS_READ BIT(0)
++#define GB_AUDIO_ACCESS_WRITE BIT(1)
++#define GB_AUDIO_ACCESS_VOLATILE BIT(2)
++#define GB_AUDIO_ACCESS_TIMESTAMP BIT(3)
++#define GB_AUDIO_ACCESS_TLV_READ BIT(4)
++#define GB_AUDIO_ACCESS_TLV_WRITE BIT(5)
++#define GB_AUDIO_ACCESS_TLV_COMMAND BIT(6)
++#define GB_AUDIO_ACCESS_INACTIVE BIT(7)
++#define GB_AUDIO_ACCESS_LOCK BIT(8)
++#define GB_AUDIO_ACCESS_OWNER BIT(9)
++
++/* enum snd_soc_dapm_type */
++#define GB_AUDIO_WIDGET_TYPE_INPUT 0x0
++#define GB_AUDIO_WIDGET_TYPE_OUTPUT 0x1
++#define GB_AUDIO_WIDGET_TYPE_MUX 0x2
++#define GB_AUDIO_WIDGET_TYPE_VIRT_MUX 0x3
++#define GB_AUDIO_WIDGET_TYPE_VALUE_MUX 0x4
++#define GB_AUDIO_WIDGET_TYPE_MIXER 0x5
++#define GB_AUDIO_WIDGET_TYPE_MIXER_NAMED_CTL 0x6
++#define GB_AUDIO_WIDGET_TYPE_PGA 0x7
++#define GB_AUDIO_WIDGET_TYPE_OUT_DRV 0x8
++#define GB_AUDIO_WIDGET_TYPE_ADC 0x9
++#define GB_AUDIO_WIDGET_TYPE_DAC 0xa
++#define GB_AUDIO_WIDGET_TYPE_MICBIAS 0xb
++#define GB_AUDIO_WIDGET_TYPE_MIC 0xc
++#define GB_AUDIO_WIDGET_TYPE_HP 0xd
++#define GB_AUDIO_WIDGET_TYPE_SPK 0xe
++#define GB_AUDIO_WIDGET_TYPE_LINE 0xf
++#define GB_AUDIO_WIDGET_TYPE_SWITCH 0x10
++#define GB_AUDIO_WIDGET_TYPE_VMID 0x11
++#define GB_AUDIO_WIDGET_TYPE_PRE 0x12
++#define GB_AUDIO_WIDGET_TYPE_POST 0x13
++#define GB_AUDIO_WIDGET_TYPE_SUPPLY 0x14
++#define GB_AUDIO_WIDGET_TYPE_REGULATOR_SUPPLY 0x15
++#define GB_AUDIO_WIDGET_TYPE_CLOCK_SUPPLY 0x16
++#define GB_AUDIO_WIDGET_TYPE_AIF_IN 0x17
++#define GB_AUDIO_WIDGET_TYPE_AIF_OUT 0x18
++#define GB_AUDIO_WIDGET_TYPE_SIGGEN 0x19
++#define GB_AUDIO_WIDGET_TYPE_DAI_IN 0x1a
++#define GB_AUDIO_WIDGET_TYPE_DAI_OUT 0x1b
++#define GB_AUDIO_WIDGET_TYPE_DAI_LINK 0x1c
++
++#define GB_AUDIO_WIDGET_STATE_DISABLED 0x01
++#define GB_AUDIO_WIDGET_STATE_ENAABLED 0x02
++
++#define GB_AUDIO_JACK_EVENT_INSERTION 0x1
++#define GB_AUDIO_JACK_EVENT_REMOVAL 0x2
++
++#define GB_AUDIO_BUTTON_EVENT_PRESS 0x1
++#define GB_AUDIO_BUTTON_EVENT_RELEASE 0x2
++
++#define GB_AUDIO_STREAMING_EVENT_UNSPECIFIED 0x1
++#define GB_AUDIO_STREAMING_EVENT_HALT 0x2
++#define GB_AUDIO_STREAMING_EVENT_INTERNAL_ERROR 0x3
++#define GB_AUDIO_STREAMING_EVENT_PROTOCOL_ERROR 0x4
++#define GB_AUDIO_STREAMING_EVENT_FAILURE 0x5
++#define GB_AUDIO_STREAMING_EVENT_UNDERRUN 0x6
++#define GB_AUDIO_STREAMING_EVENT_OVERRUN 0x7
++#define GB_AUDIO_STREAMING_EVENT_CLOCKING 0x8
++#define GB_AUDIO_STREAMING_EVENT_DATA_LEN 0x9
++
++#define GB_AUDIO_INVALID_INDEX 0xff
++
++/* enum snd_jack_types */
++#define GB_AUDIO_JACK_HEADPHONE 0x0000001
++#define GB_AUDIO_JACK_MICROPHONE 0x0000002
++#define GB_AUDIO_JACK_HEADSET (GB_AUDIO_JACK_HEADPHONE | \
++ GB_AUDIO_JACK_MICROPHONE)
++#define GB_AUDIO_JACK_LINEOUT 0x0000004
++#define GB_AUDIO_JACK_MECHANICAL 0x0000008
++#define GB_AUDIO_JACK_VIDEOOUT 0x0000010
++#define GB_AUDIO_JACK_AVOUT (GB_AUDIO_JACK_LINEOUT | \
++ GB_AUDIO_JACK_VIDEOOUT)
++#define GB_AUDIO_JACK_LINEIN 0x0000020
++#define GB_AUDIO_JACK_OC_HPHL 0x0000040
++#define GB_AUDIO_JACK_OC_HPHR 0x0000080
++#define GB_AUDIO_JACK_MICROPHONE2 0x0000200
++#define GB_AUDIO_JACK_ANC_HEADPHONE (GB_AUDIO_JACK_HEADPHONE | \
++ GB_AUDIO_JACK_MICROPHONE | \
++ GB_AUDIO_JACK_MICROPHONE2)
++/* Kept separate from switches to facilitate implementation */
++#define GB_AUDIO_JACK_BTN_0 0x4000000
++#define GB_AUDIO_JACK_BTN_1 0x2000000
++#define GB_AUDIO_JACK_BTN_2 0x1000000
++#define GB_AUDIO_JACK_BTN_3 0x0800000
++
++struct gb_audio_pcm {
++ __u8 stream_name[GB_AUDIO_PCM_NAME_MAX];
++ __le32 formats; /* GB_AUDIO_PCM_FMT_* */
++ __le32 rates; /* GB_AUDIO_PCM_RATE_* */
++ __u8 chan_min;
++ __u8 chan_max;
++ __u8 sig_bits; /* number of bits of content */
++} __packed;
++
++struct gb_audio_dai {
++ __u8 name[AUDIO_DAI_NAME_MAX];
++ __le16 data_cport;
++ struct gb_audio_pcm capture;
++ struct gb_audio_pcm playback;
++} __packed;
++
++struct gb_audio_integer {
++ __le32 min;
++ __le32 max;
++ __le32 step;
++} __packed;
++
++struct gb_audio_integer64 {
++ __le64 min;
++ __le64 max;
++ __le64 step;
++} __packed;
++
++struct gb_audio_enumerated {
++ __le32 items;
++ __le16 names_length;
++ __u8 names[0];
++} __packed;
++
++struct gb_audio_ctl_elem_info { /* See snd_ctl_elem_info in Linux source */
++ __u8 type; /* GB_AUDIO_CTL_ELEM_TYPE_* */
++ __le16 dimen[4];
++ union {
++ struct gb_audio_integer integer;
++ struct gb_audio_integer64 integer64;
++ struct gb_audio_enumerated enumerated;
++ } value;
++} __packed;
++
++struct gb_audio_ctl_elem_value { /* See snd_ctl_elem_value in Linux source */
++ __le64 timestamp; /* XXX needed? */
++ union {
++ __le32 integer_value[2]; /* consider CTL_DOUBLE_xxx */
++ __le64 integer64_value[2];
++ __le32 enumerated_item[2];
++ } value;
++} __packed;
++
++struct gb_audio_control {
++ __u8 name[AUDIO_CONTROL_NAME_MAX];
++ __u8 id; /* 0-63 */
++ __u8 iface; /* GB_AUDIO_IFACE_* */
++ __le16 data_cport;
++ __le32 access; /* GB_AUDIO_ACCESS_* */
++ __u8 count; /* count of same elements */
++ __u8 count_values; /* count of values, max=2 for CTL_DOUBLE_xxx */
++ struct gb_audio_ctl_elem_info info;
++} __packed;
++
++struct gb_audio_widget {
++ __u8 name[AUDIO_WIDGET_NAME_MAX];
++ __u8 sname[AUDIO_WIDGET_NAME_MAX];
++ __u8 id;
++ __u8 type; /* GB_AUDIO_WIDGET_TYPE_* */
++ __u8 state; /* GB_AUDIO_WIDGET_STATE_* */
++ __u8 ncontrols;
++ struct gb_audio_control ctl[0]; /* 'ncontrols' entries */
++} __packed;
++
++struct gb_audio_route {
++ __u8 source_id; /* widget id */
++ __u8 destination_id; /* widget id */
++ __u8 control_id; /* 0-63 */
++ __u8 index; /* Selection within the control */
++} __packed;
++
++struct gb_audio_topology {
++ __u8 num_dais;
++ __u8 num_controls;
++ __u8 num_widgets;
++ __u8 num_routes;
++ __le32 size_dais;
++ __le32 size_controls;
++ __le32 size_widgets;
++ __le32 size_routes;
++ __le32 jack_type;
++ /*
++ * struct gb_audio_dai dai[num_dais];
++ * struct gb_audio_control controls[num_controls];
++ * struct gb_audio_widget widgets[num_widgets];
++ * struct gb_audio_route routes[num_routes];
++ */
++ __u8 data[0];
++} __packed;
++
++struct gb_audio_get_topology_size_response {
++ __le16 size;
++} __packed;
++
++struct gb_audio_get_topology_response {
++ struct gb_audio_topology topology;
++} __packed;
++
++struct gb_audio_get_control_request {
++ __u8 control_id;
++ __u8 index;
++} __packed;
++
++struct gb_audio_get_control_response {
++ struct gb_audio_ctl_elem_value value;
++} __packed;
++
++struct gb_audio_set_control_request {
++ __u8 control_id;
++ __u8 index;
++ struct gb_audio_ctl_elem_value value;
++} __packed;
++
++struct gb_audio_enable_widget_request {
++ __u8 widget_id;
++} __packed;
++
++struct gb_audio_disable_widget_request {
++ __u8 widget_id;
++} __packed;
++
++struct gb_audio_get_pcm_request {
++ __le16 data_cport;
++} __packed;
++
++struct gb_audio_get_pcm_response {
++ __le32 format;
++ __le32 rate;
++ __u8 channels;
++ __u8 sig_bits;
++} __packed;
++
++struct gb_audio_set_pcm_request {
++ __le16 data_cport;
++ __le32 format;
++ __le32 rate;
++ __u8 channels;
++ __u8 sig_bits;
++} __packed;
++
++struct gb_audio_set_tx_data_size_request {
++ __le16 data_cport;
++ __le16 size;
++} __packed;
++
++struct gb_audio_activate_tx_request {
++ __le16 data_cport;
++} __packed;
++
++struct gb_audio_deactivate_tx_request {
++ __le16 data_cport;
++} __packed;
++
++struct gb_audio_set_rx_data_size_request {
++ __le16 data_cport;
++ __le16 size;
++} __packed;
++
++struct gb_audio_activate_rx_request {
++ __le16 data_cport;
++} __packed;
++
++struct gb_audio_deactivate_rx_request {
++ __le16 data_cport;
++} __packed;
++
++struct gb_audio_jack_event_request {
++ __u8 widget_id;
++ __u8 jack_attribute;
++ __u8 event;
++} __packed;
++
++struct gb_audio_button_event_request {
++ __u8 widget_id;
++ __u8 button_id;
++ __u8 event;
++} __packed;
++
++struct gb_audio_streaming_event_request {
++ __le16 data_cport;
++ __u8 event;
++} __packed;
++
++struct gb_audio_send_data_request {
++ __le64 timestamp;
++ __u8 data[0];
++} __packed;
++
++
++/* Log */
++
++/* operations */
++#define GB_LOG_TYPE_SEND_LOG 0x02
++
++/* length */
++#define GB_LOG_MAX_LEN 1024
++
++struct gb_log_send_log_request {
++ __le16 len;
++ __u8 msg[0];
++} __packed;
++
++#endif /* __GREYBUS_PROTOCOLS_H */
++
diff --git a/greybus_pwm.patch b/greybus_pwm.patch
new file mode 100644
index 00000000000000..3f6ad0059d2052
--- /dev/null
+++ b/greybus_pwm.patch
@@ -0,0 +1,345 @@
+---
+ drivers/greybus/pwm.c | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 338 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/pwm.c
+@@ -0,0 +1,338 @@
++/*
++ * PWM Greybus driver.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/pwm.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++struct gb_pwm_chip {
++ struct gb_connection *connection;
++ u8 pwm_max; /* max pwm number */
++
++ struct pwm_chip chip;
++ struct pwm_chip *pwm;
++};
++#define pwm_chip_to_gb_pwm_chip(chip) \
++ container_of(chip, struct gb_pwm_chip, chip)
++
++
++static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
++{
++ struct gb_pwm_count_response response;
++ int ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
++ NULL, 0, &response, sizeof(response));
++ if (ret)
++ return ret;
++ pwmc->pwm_max = response.count;
++ return 0;
++}
++
++static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
++ u8 which)
++{
++ struct gb_pwm_activate_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,
++ &request, sizeof(request), NULL, 0);
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
++ u8 which)
++{
++ struct gb_pwm_deactivate_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,
++ &request, sizeof(request), NULL, 0);
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
++ u8 which, u32 duty, u32 period)
++{
++ struct gb_pwm_config_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++ request.duty = cpu_to_le32(duty);
++ request.period = cpu_to_le32(period);
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,
++ &request, sizeof(request), NULL, 0);
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
++ u8 which, u8 polarity)
++{
++ struct gb_pwm_polarity_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++ request.polarity = polarity;
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,
++ &request, sizeof(request), NULL, 0);
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
++ u8 which)
++{
++ struct gb_pwm_enable_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,
++ &request, sizeof(request), NULL, 0);
++ if (ret)
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
++ u8 which)
++{
++ struct gb_pwm_disable_request request;
++ struct gbphy_device *gbphy_dev;
++ int ret;
++
++ if (which > pwmc->pwm_max)
++ return -EINVAL;
++
++ request.which = which;
++
++ ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
++ &request, sizeof(request), NULL, 0);
++
++ gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++}
++
++static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
++};
++
++static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ if (pwm_is_enabled(pwm))
++ dev_warn(chip->dev, "freeing PWM device without disabling\n");
++
++ gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
++}
++
++static int gb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ return gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_ns, period_ns);
++};
++
++static int gb_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
++ enum pwm_polarity polarity)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ return gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, polarity);
++};
++
++static int gb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
++};
++
++static void gb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
++
++ gb_pwm_disable_operation(pwmc, pwm->hwpwm);
++};
++
++static const struct pwm_ops gb_pwm_ops = {
++ .request = gb_pwm_request,
++ .free = gb_pwm_free,
++ .config = gb_pwm_config,
++ .set_polarity = gb_pwm_set_polarity,
++ .enable = gb_pwm_enable,
++ .disable = gb_pwm_disable,
++ .owner = THIS_MODULE,
++};
++
++static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ struct gb_pwm_chip *pwmc;
++ struct pwm_chip *pwm;
++ int ret;
++
++ pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
++ if (!pwmc)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ NULL);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto exit_pwmc_free;
++ }
++
++ pwmc->connection = connection;
++ gb_connection_set_data(connection, pwmc);
++ gb_gbphy_set_data(gbphy_dev, pwmc);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto exit_connection_destroy;
++
++ /* Query number of pwms present */
++ ret = gb_pwm_count_operation(pwmc);
++ if (ret)
++ goto exit_connection_disable;
++
++ pwm = &pwmc->chip;
++
++ pwm->dev = &gbphy_dev->dev;
++ pwm->ops = &gb_pwm_ops;
++ pwm->base = -1; /* Allocate base dynamically */
++ pwm->npwm = pwmc->pwm_max + 1;
++ pwm->can_sleep = true; /* FIXME */
++
++ ret = pwmchip_add(pwm);
++ if (ret) {
++ dev_err(&gbphy_dev->dev,
++ "failed to register PWM: %d\n", ret);
++ goto exit_connection_disable;
++ }
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return 0;
++
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_pwmc_free:
++ kfree(pwmc);
++ return ret;
++}
++
++static void gb_pwm_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_pwm_chip *pwmc = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = pwmc->connection;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ pwmchip_remove(&pwmc->chip);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++ kfree(pwmc);
++}
++
++static const struct gbphy_device_id gb_pwm_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_PWM) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_pwm_id_table);
++
++static struct gbphy_driver pwm_driver = {
++ .name = "pwm",
++ .probe = gb_pwm_probe,
++ .remove = gb_pwm_remove,
++ .id_table = gb_pwm_id_table,
++};
++
++module_gbphy_driver(pwm_driver);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_raw.patch b/greybus_raw.patch
new file mode 100644
index 00000000000000..ea821a4f4d541f
--- /dev/null
+++ b/greybus_raw.patch
@@ -0,0 +1,388 @@
+---
+ drivers/greybus/raw.c | 381 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 381 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/raw.c
+@@ -0,0 +1,381 @@
++/*
++ * Greybus driver for the Raw protocol
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sizes.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/idr.h>
++#include <linux/uaccess.h>
++
++#include "greybus.h"
++
++struct gb_raw {
++ struct gb_connection *connection;
++
++ struct list_head list;
++ int list_data;
++ struct mutex list_lock;
++ dev_t dev;
++ struct cdev cdev;
++ struct device *device;
++};
++
++struct raw_data {
++ struct list_head entry;
++ u32 len;
++ u8 data[0];
++};
++
++static struct class *raw_class;
++static int raw_major;
++static const struct file_operations raw_fops;
++static DEFINE_IDA(minors);
++
++/* Number of minor devices this driver supports */
++#define NUM_MINORS 256
++
++/* Maximum size of any one send data buffer we support */
++#define MAX_PACKET_SIZE (PAGE_SIZE * 2)
++
++/*
++ * Maximum size of the data in the receive buffer we allow before we start to
++ * drop messages on the floor
++ */
++#define MAX_DATA_SIZE (MAX_PACKET_SIZE * 8)
++
++/*
++ * Add the raw data message to the list of received messages.
++ */
++static int receive_data(struct gb_raw *raw, u32 len, u8 *data)
++{
++ struct raw_data *raw_data;
++ struct device *dev = &raw->connection->bundle->dev;
++ int retval = 0;
++
++ if (len > MAX_PACKET_SIZE) {
++ dev_err(dev, "Too big of a data packet, rejected\n");
++ return -EINVAL;
++ }
++
++ mutex_lock(&raw->list_lock);
++ if ((raw->list_data + len) > MAX_DATA_SIZE) {
++ dev_err(dev, "Too much data in receive buffer, now dropping packets\n");
++ retval = -EINVAL;
++ goto exit;
++ }
++
++ raw_data = kmalloc(sizeof(*raw_data) + len, GFP_KERNEL);
++ if (!raw_data) {
++ retval = -ENOMEM;
++ goto exit;
++ }
++
++ raw->list_data += len;
++ raw_data->len = len;
++ memcpy(&raw_data->data[0], data, len);
++
++ list_add_tail(&raw_data->entry, &raw->list);
++exit:
++ mutex_unlock(&raw->list_lock);
++ return retval;
++}
++
++static int gb_raw_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct device *dev = &connection->bundle->dev;
++ struct gb_raw *raw = greybus_get_drvdata(connection->bundle);
++ struct gb_raw_send_request *receive;
++ u32 len;
++
++ if (op->type != GB_RAW_TYPE_SEND) {
++ dev_err(dev, "unknown request type 0x%02x\n", op->type);
++ return -EINVAL;
++ }
++
++ /* Verify size of payload */
++ if (op->request->payload_size < sizeof(*receive)) {
++ dev_err(dev, "raw receive request too small (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*receive));
++ return -EINVAL;
++ }
++ receive = op->request->payload;
++ len = le32_to_cpu(receive->len);
++ if (len != (int)(op->request->payload_size - sizeof(__le32))) {
++ dev_err(dev, "raw receive request wrong size %d vs %d\n", len,
++ (int)(op->request->payload_size - sizeof(__le32)));
++ return -EINVAL;
++ }
++ if (len == 0) {
++ dev_err(dev, "raw receive request of 0 bytes?\n");
++ return -EINVAL;
++ }
++
++ return receive_data(raw, len, receive->data);
++}
++
++static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
++{
++ struct gb_connection *connection = raw->connection;
++ struct gb_raw_send_request *request;
++ int retval;
++
++ request = kmalloc(len + sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ if (copy_from_user(&request->data[0], data, len)) {
++ kfree(request);
++ return -EFAULT;
++ }
++
++ request->len = cpu_to_le32(len);
++
++ retval = gb_operation_sync(connection, GB_RAW_TYPE_SEND,
++ request, len + sizeof(*request),
++ NULL, 0);
++
++ kfree(request);
++ return retval;
++}
++
++static int gb_raw_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_raw *raw;
++ int retval;
++ int minor;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)
++ return -ENODEV;
++
++ raw = kzalloc(sizeof(*raw), GFP_KERNEL);
++ if (!raw)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ gb_raw_request_handler);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto error_free;
++ }
++
++ INIT_LIST_HEAD(&raw->list);
++ mutex_init(&raw->list_lock);
++
++ raw->connection = connection;
++ greybus_set_drvdata(bundle, raw);
++
++ minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
++ if (minor < 0) {
++ retval = minor;
++ goto error_connection_destroy;
++ }
++
++ raw->dev = MKDEV(raw_major, minor);
++ cdev_init(&raw->cdev, &raw_fops);
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto error_remove_ida;
++
++ retval = cdev_add(&raw->cdev, raw->dev, 1);
++ if (retval)
++ goto error_connection_disable;
++
++ raw->device = device_create(raw_class, &connection->bundle->dev,
++ raw->dev, raw, "gb!raw%d", minor);
++ if (IS_ERR(raw->device)) {
++ retval = PTR_ERR(raw->device);
++ goto error_del_cdev;
++ }
++
++ return 0;
++
++error_del_cdev:
++ cdev_del(&raw->cdev);
++
++error_connection_disable:
++ gb_connection_disable(connection);
++
++error_remove_ida:
++ ida_simple_remove(&minors, minor);
++
++error_connection_destroy:
++ gb_connection_destroy(connection);
++
++error_free:
++ kfree(raw);
++ return retval;
++}
++
++static void gb_raw_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_raw *raw = greybus_get_drvdata(bundle);
++ struct gb_connection *connection = raw->connection;
++ struct raw_data *raw_data;
++ struct raw_data *temp;
++
++ // FIXME - handle removing a connection when the char device node is open.
++ device_destroy(raw_class, raw->dev);
++ cdev_del(&raw->cdev);
++ gb_connection_disable(connection);
++ ida_simple_remove(&minors, MINOR(raw->dev));
++ gb_connection_destroy(connection);
++
++ mutex_lock(&raw->list_lock);
++ list_for_each_entry_safe(raw_data, temp, &raw->list, entry) {
++ list_del(&raw_data->entry);
++ kfree(raw_data);
++ }
++ mutex_unlock(&raw->list_lock);
++
++ kfree(raw);
++}
++
++/*
++ * Character device node interfaces.
++ *
++ * Note, we are using read/write to only allow a single read/write per message.
++ * This means for read(), you have to provide a big enough buffer for the full
++ * message to be copied into. If the buffer isn't big enough, the read() will
++ * fail with -ENOSPC.
++ */
++
++static int raw_open(struct inode *inode, struct file *file)
++{
++ struct cdev *cdev = inode->i_cdev;
++ struct gb_raw *raw = container_of(cdev, struct gb_raw, cdev);
++
++ file->private_data = raw;
++ return 0;
++}
++
++static ssize_t raw_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct gb_raw *raw = file->private_data;
++ int retval;
++
++ if (!count)
++ return 0;
++
++ if (count > MAX_PACKET_SIZE)
++ return -E2BIG;
++
++ retval = gb_raw_send(raw, count, buf);
++ if (retval)
++ return retval;
++
++ return count;
++}
++
++static ssize_t raw_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ struct gb_raw *raw = file->private_data;
++ int retval = 0;
++ struct raw_data *raw_data;
++
++ mutex_lock(&raw->list_lock);
++ if (list_empty(&raw->list))
++ goto exit;
++
++ raw_data = list_first_entry(&raw->list, struct raw_data, entry);
++ if (raw_data->len > count) {
++ retval = -ENOSPC;
++ goto exit;
++ }
++
++ if (copy_to_user(buf, &raw_data->data[0], raw_data->len)) {
++ retval = -EFAULT;
++ goto exit;
++ }
++
++ list_del(&raw_data->entry);
++ raw->list_data -= raw_data->len;
++ retval = raw_data->len;
++ kfree(raw_data);
++
++exit:
++ mutex_unlock(&raw->list_lock);
++ return retval;
++}
++
++static const struct file_operations raw_fops = {
++ .owner = THIS_MODULE,
++ .write = raw_write,
++ .read = raw_read,
++ .open = raw_open,
++ .llseek = noop_llseek,
++};
++
++static const struct greybus_bundle_id gb_raw_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_raw_id_table);
++
++static struct greybus_driver gb_raw_driver = {
++ .name = "raw",
++ .probe = gb_raw_probe,
++ .disconnect = gb_raw_disconnect,
++ .id_table = gb_raw_id_table,
++};
++
++static int raw_init(void)
++{
++ dev_t dev;
++ int retval;
++
++ raw_class = class_create(THIS_MODULE, "gb_raw");
++ if (IS_ERR(raw_class)) {
++ retval = PTR_ERR(raw_class);
++ goto error_class;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, NUM_MINORS, "gb_raw");
++ if (retval < 0)
++ goto error_chrdev;
++
++ raw_major = MAJOR(dev);
++
++ retval = greybus_register(&gb_raw_driver);
++ if (retval)
++ goto error_gb;
++
++ return 0;
++
++error_gb:
++ unregister_chrdev_region(dev, NUM_MINORS);
++error_chrdev:
++ class_destroy(raw_class);
++error_class:
++ return retval;
++}
++module_init(raw_init);
++
++static void __exit raw_exit(void)
++{
++ greybus_deregister(&gb_raw_driver);
++ unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS);
++ class_destroy(raw_class);
++ ida_destroy(&minors);
++}
++module_exit(raw_exit);
++
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_sdio.patch b/greybus_sdio.patch
new file mode 100644
index 00000000000000..32e0d3af6d5804
--- /dev/null
+++ b/greybus_sdio.patch
@@ -0,0 +1,891 @@
+---
+ drivers/greybus/sdio.c | 884 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 884 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/sdio.c
+@@ -0,0 +1,884 @@
++/*
++ * SD/MMC Greybus driver.
++ *
++ * Copyright 2014-2015 Google Inc.
++ * Copyright 2014-2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/mmc/core.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/mmc.h>
++#include <linux/scatterlist.h>
++#include <linux/workqueue.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++struct gb_sdio_host {
++ struct gb_connection *connection;
++ struct gbphy_device *gbphy_dev;
++ struct mmc_host *mmc;
++ struct mmc_request *mrq;
++ struct mutex lock; /* lock for this host */
++ size_t data_max;
++ spinlock_t xfer; /* lock to cancel ongoing transfer */
++ bool xfer_stop;
++ struct workqueue_struct *mrq_workqueue;
++ struct work_struct mrqwork;
++ u8 queued_events;
++ bool removed;
++ bool card_present;
++ bool read_only;
++};
++
++
++#define GB_SDIO_RSP_R1_R5_R6_R7 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
++ GB_SDIO_RSP_OPCODE)
++#define GB_SDIO_RSP_R3_R4 (GB_SDIO_RSP_PRESENT)
++#define GB_SDIO_RSP_R2 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
++ GB_SDIO_RSP_136)
++#define GB_SDIO_RSP_R1B (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
++ GB_SDIO_RSP_OPCODE | GB_SDIO_RSP_BUSY)
++
++/* kernel vdd starts at 0x80 and we need to translate to greybus ones 0x01 */
++#define GB_SDIO_VDD_SHIFT 8
++
++#ifndef MMC_CAP2_CORE_RUNTIME_PM
++#define MMC_CAP2_CORE_RUNTIME_PM 0
++#endif
++
++static inline bool single_op(struct mmc_command *cmd)
++{
++ uint32_t opcode = cmd->opcode;
++
++ return opcode == MMC_WRITE_BLOCK ||
++ opcode == MMC_READ_SINGLE_BLOCK;
++}
++
++static void _gb_sdio_set_host_caps(struct gb_sdio_host *host, u32 r)
++{
++ u32 caps = 0;
++ u32 caps2 = 0;
++
++ caps = ((r & GB_SDIO_CAP_NONREMOVABLE) ? MMC_CAP_NONREMOVABLE : 0) |
++ ((r & GB_SDIO_CAP_4_BIT_DATA) ? MMC_CAP_4_BIT_DATA : 0) |
++ ((r & GB_SDIO_CAP_8_BIT_DATA) ? MMC_CAP_8_BIT_DATA : 0) |
++ ((r & GB_SDIO_CAP_MMC_HS) ? MMC_CAP_MMC_HIGHSPEED : 0) |
++ ((r & GB_SDIO_CAP_SD_HS) ? MMC_CAP_SD_HIGHSPEED : 0) |
++ ((r & GB_SDIO_CAP_ERASE) ? MMC_CAP_ERASE : 0) |
++ ((r & GB_SDIO_CAP_1_2V_DDR) ? MMC_CAP_1_2V_DDR : 0) |
++ ((r & GB_SDIO_CAP_1_8V_DDR) ? MMC_CAP_1_8V_DDR : 0) |
++ ((r & GB_SDIO_CAP_POWER_OFF_CARD) ? MMC_CAP_POWER_OFF_CARD : 0) |
++ ((r & GB_SDIO_CAP_UHS_SDR12) ? MMC_CAP_UHS_SDR12 : 0) |
++ ((r & GB_SDIO_CAP_UHS_SDR25) ? MMC_CAP_UHS_SDR25 : 0) |
++ ((r & GB_SDIO_CAP_UHS_SDR50) ? MMC_CAP_UHS_SDR50 : 0) |
++ ((r & GB_SDIO_CAP_UHS_SDR104) ? MMC_CAP_UHS_SDR104 : 0) |
++ ((r & GB_SDIO_CAP_UHS_DDR50) ? MMC_CAP_UHS_DDR50 : 0) |
++ ((r & GB_SDIO_CAP_DRIVER_TYPE_A) ? MMC_CAP_DRIVER_TYPE_A : 0) |
++ ((r & GB_SDIO_CAP_DRIVER_TYPE_C) ? MMC_CAP_DRIVER_TYPE_C : 0) |
++ ((r & GB_SDIO_CAP_DRIVER_TYPE_D) ? MMC_CAP_DRIVER_TYPE_D : 0);
++
++ caps2 = ((r & GB_SDIO_CAP_HS200_1_2V) ? MMC_CAP2_HS200_1_2V_SDR : 0) |
++ ((r & GB_SDIO_CAP_HS400_1_2V) ? MMC_CAP2_HS400_1_2V : 0) |
++ ((r & GB_SDIO_CAP_HS400_1_8V) ? MMC_CAP2_HS400_1_8V : 0) |
++ ((r & GB_SDIO_CAP_HS200_1_8V) ? MMC_CAP2_HS200_1_8V_SDR : 0);
++
++ host->mmc->caps = caps;
++ host->mmc->caps2 = caps2 | MMC_CAP2_CORE_RUNTIME_PM;
++
++ if (caps & MMC_CAP_NONREMOVABLE)
++ host->card_present = true;
++}
++
++static u32 _gb_sdio_get_host_ocr(u32 ocr)
++{
++ return (((ocr & GB_SDIO_VDD_165_195) ? MMC_VDD_165_195 : 0) |
++ ((ocr & GB_SDIO_VDD_20_21) ? MMC_VDD_20_21 : 0) |
++ ((ocr & GB_SDIO_VDD_21_22) ? MMC_VDD_21_22 : 0) |
++ ((ocr & GB_SDIO_VDD_22_23) ? MMC_VDD_22_23 : 0) |
++ ((ocr & GB_SDIO_VDD_23_24) ? MMC_VDD_23_24 : 0) |
++ ((ocr & GB_SDIO_VDD_24_25) ? MMC_VDD_24_25 : 0) |
++ ((ocr & GB_SDIO_VDD_25_26) ? MMC_VDD_25_26 : 0) |
++ ((ocr & GB_SDIO_VDD_26_27) ? MMC_VDD_26_27 : 0) |
++ ((ocr & GB_SDIO_VDD_27_28) ? MMC_VDD_27_28 : 0) |
++ ((ocr & GB_SDIO_VDD_28_29) ? MMC_VDD_28_29 : 0) |
++ ((ocr & GB_SDIO_VDD_29_30) ? MMC_VDD_29_30 : 0) |
++ ((ocr & GB_SDIO_VDD_30_31) ? MMC_VDD_30_31 : 0) |
++ ((ocr & GB_SDIO_VDD_31_32) ? MMC_VDD_31_32 : 0) |
++ ((ocr & GB_SDIO_VDD_32_33) ? MMC_VDD_32_33 : 0) |
++ ((ocr & GB_SDIO_VDD_33_34) ? MMC_VDD_33_34 : 0) |
++ ((ocr & GB_SDIO_VDD_34_35) ? MMC_VDD_34_35 : 0) |
++ ((ocr & GB_SDIO_VDD_35_36) ? MMC_VDD_35_36 : 0)
++ );
++}
++
++static int gb_sdio_get_caps(struct gb_sdio_host *host)
++{
++ struct gb_sdio_get_caps_response response;
++ struct mmc_host *mmc = host->mmc;
++ u16 data_max;
++ u32 blksz;
++ u32 ocr;
++ u32 r;
++ int ret;
++
++ ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_GET_CAPABILITIES,
++ NULL, 0, &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++ r = le32_to_cpu(response.caps);
++
++ _gb_sdio_set_host_caps(host, r);
++
++ /* get the max block size that could fit our payload */
++ data_max = gb_operation_get_payload_size_max(host->connection);
++ data_max = min(data_max - sizeof(struct gb_sdio_transfer_request),
++ data_max - sizeof(struct gb_sdio_transfer_response));
++
++ blksz = min_t(u16, le16_to_cpu(response.max_blk_size), data_max);
++ blksz = max_t(u32, 512, blksz);
++
++ mmc->max_blk_size = rounddown_pow_of_two(blksz);
++ mmc->max_blk_count = le16_to_cpu(response.max_blk_count);
++ host->data_max = data_max;
++
++ /* get ocr supported values */
++ ocr = _gb_sdio_get_host_ocr(le32_to_cpu(response.ocr));
++ mmc->ocr_avail = ocr;
++ mmc->ocr_avail_sdio = mmc->ocr_avail;
++ mmc->ocr_avail_sd = mmc->ocr_avail;
++ mmc->ocr_avail_mmc = mmc->ocr_avail;
++
++ /* get frequency range values */
++ mmc->f_min = le32_to_cpu(response.f_min);
++ mmc->f_max = le32_to_cpu(response.f_max);
++
++ return 0;
++}
++
++static void _gb_queue_event(struct gb_sdio_host *host, u8 event)
++{
++ if (event & GB_SDIO_CARD_INSERTED)
++ host->queued_events &= ~GB_SDIO_CARD_REMOVED;
++ else if (event & GB_SDIO_CARD_REMOVED)
++ host->queued_events &= ~GB_SDIO_CARD_INSERTED;
++
++ host->queued_events |= event;
++}
++
++static int _gb_sdio_process_events(struct gb_sdio_host *host, u8 event)
++{
++ u8 state_changed = 0;
++
++ if (event & GB_SDIO_CARD_INSERTED) {
++ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
++ return 0;
++ if (host->card_present)
++ return 0;
++ host->card_present = true;
++ state_changed = 1;
++ }
++
++ if (event & GB_SDIO_CARD_REMOVED) {
++ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
++ return 0;
++ if (!(host->card_present))
++ return 0;
++ host->card_present = false;
++ state_changed = 1;
++ }
++
++ if (event & GB_SDIO_WP) {
++ host->read_only = true;
++ }
++
++ if (state_changed) {
++ dev_info(mmc_dev(host->mmc), "card %s now event\n",
++ (host->card_present ? "inserted" : "removed"));
++ mmc_detect_change(host->mmc, 0);
++ }
++
++ return 0;
++}
++
++static int gb_sdio_request_handler(struct gb_operation *op)
++{
++ struct gb_sdio_host *host = gb_connection_get_data(op->connection);
++ struct gb_message *request;
++ struct gb_sdio_event_request *payload;
++ u8 type = op->type;
++ int ret = 0;
++ u8 event;
++
++ if (type != GB_SDIO_TYPE_EVENT) {
++ dev_err(mmc_dev(host->mmc),
++ "unsupported unsolicited event: %u\n", type);
++ return -EINVAL;
++ }
++
++ request = op->request;
++
++ if (request->payload_size < sizeof(*payload)) {
++ dev_err(mmc_dev(host->mmc), "wrong event size received (%zu < %zu)\n",
++ request->payload_size, sizeof(*payload));
++ return -EINVAL;
++ }
++
++ payload = request->payload;
++ event = payload->event;
++
++ if (host->removed)
++ _gb_queue_event(host, event);
++ else
++ ret = _gb_sdio_process_events(host, event);
++
++ return ret;
++}
++
++static int gb_sdio_set_ios(struct gb_sdio_host *host,
++ struct gb_sdio_set_ios_request *request)
++{
++ int ret;
++
++ ret = gbphy_runtime_get_sync(host->gbphy_dev);
++ if (ret)
++ return ret;
++
++ ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_SET_IOS, request,
++ sizeof(*request), NULL, 0);
++
++ gbphy_runtime_put_autosuspend(host->gbphy_dev);
++
++ return ret;
++}
++
++static int _gb_sdio_send(struct gb_sdio_host *host, struct mmc_data *data,
++ size_t len, u16 nblocks, off_t skip)
++{
++ struct gb_sdio_transfer_request *request;
++ struct gb_sdio_transfer_response *response;
++ struct gb_operation *operation;
++ struct scatterlist *sg = data->sg;
++ unsigned int sg_len = data->sg_len;
++ size_t copied;
++ u16 send_blksz;
++ u16 send_blocks;
++ int ret;
++
++ WARN_ON(len > host->data_max);
++
++ operation = gb_operation_create(host->connection, GB_SDIO_TYPE_TRANSFER,
++ len + sizeof(*request),
++ sizeof(*response), GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ request = operation->request->payload;
++ request->data_flags = (data->flags >> 8);
++ request->data_blocks = cpu_to_le16(nblocks);
++ request->data_blksz = cpu_to_le16(data->blksz);
++
++ copied = sg_pcopy_to_buffer(sg, sg_len, &request->data[0], len, skip);
++
++ if (copied != len) {
++ ret = -EINVAL;
++ goto err_put_operation;
++ }
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret < 0)
++ goto err_put_operation;
++
++ response = operation->response->payload;
++
++ send_blocks = le16_to_cpu(response->data_blocks);
++ send_blksz = le16_to_cpu(response->data_blksz);
++
++ if (len != send_blksz * send_blocks) {
++ dev_err(mmc_dev(host->mmc), "send: size received: %zu != %d\n",
++ len, send_blksz * send_blocks);
++ ret = -EINVAL;
++ }
++
++err_put_operation:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static int _gb_sdio_recv(struct gb_sdio_host *host, struct mmc_data *data,
++ size_t len, u16 nblocks, off_t skip)
++{
++ struct gb_sdio_transfer_request *request;
++ struct gb_sdio_transfer_response *response;
++ struct gb_operation *operation;
++ struct scatterlist *sg = data->sg;
++ unsigned int sg_len = data->sg_len;
++ size_t copied;
++ u16 recv_blksz;
++ u16 recv_blocks;
++ int ret;
++
++ WARN_ON(len > host->data_max);
++
++ operation = gb_operation_create(host->connection, GB_SDIO_TYPE_TRANSFER,
++ sizeof(*request),
++ len + sizeof(*response), GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ request = operation->request->payload;
++ request->data_flags = (data->flags >> 8);
++ request->data_blocks = cpu_to_le16(nblocks);
++ request->data_blksz = cpu_to_le16(data->blksz);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret < 0)
++ goto err_put_operation;
++
++ response = operation->response->payload;
++ recv_blocks = le16_to_cpu(response->data_blocks);
++ recv_blksz = le16_to_cpu(response->data_blksz);
++
++ if (len != recv_blksz * recv_blocks) {
++ dev_err(mmc_dev(host->mmc), "recv: size received: %d != %zu\n",
++ recv_blksz * recv_blocks, len);
++ ret = -EINVAL;
++ goto err_put_operation;
++ }
++
++ copied = sg_pcopy_from_buffer(sg, sg_len, &response->data[0], len,
++ skip);
++ if (copied != len)
++ ret = -EINVAL;
++
++err_put_operation:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static int gb_sdio_transfer(struct gb_sdio_host *host, struct mmc_data *data)
++{
++ size_t left, len;
++ off_t skip = 0;
++ int ret = 0;
++ u16 nblocks;
++
++ if (single_op(data->mrq->cmd) && data->blocks > 1) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ left = data->blksz * data->blocks;
++
++ while (left) {
++ /* check is a stop transmission is pending */
++ spin_lock(&host->xfer);
++ if (host->xfer_stop) {
++ host->xfer_stop = false;
++ spin_unlock(&host->xfer);
++ ret = -EINTR;
++ goto out;
++ }
++ spin_unlock(&host->xfer);
++ len = min(left, host->data_max);
++ nblocks = len / data->blksz;
++ len = nblocks * data->blksz;
++
++ if (data->flags & MMC_DATA_READ) {
++ ret = _gb_sdio_recv(host, data, len, nblocks, skip);
++ if (ret < 0)
++ goto out;
++ } else {
++ ret = _gb_sdio_send(host, data, len, nblocks, skip);
++ if (ret < 0)
++ goto out;
++ }
++ data->bytes_xfered += len;
++ left -= len;
++ skip += len;
++ }
++
++out:
++ data->error = ret;
++ return ret;
++}
++
++static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd)
++{
++ struct gb_sdio_command_request request = {0};
++ struct gb_sdio_command_response response;
++ struct mmc_data *data = host->mrq->data;
++ u8 cmd_flags;
++ u8 cmd_type;
++ int i;
++ int ret;
++
++ switch (mmc_resp_type(cmd)) {
++ case MMC_RSP_NONE:
++ cmd_flags = GB_SDIO_RSP_NONE;
++ break;
++ case MMC_RSP_R1:
++ cmd_flags = GB_SDIO_RSP_R1_R5_R6_R7;
++ break;
++ case MMC_RSP_R1B:
++ cmd_flags = GB_SDIO_RSP_R1B;
++ break;
++ case MMC_RSP_R2:
++ cmd_flags = GB_SDIO_RSP_R2;
++ break;
++ case MMC_RSP_R3:
++ cmd_flags = GB_SDIO_RSP_R3_R4;
++ break;
++ default:
++ dev_err(mmc_dev(host->mmc), "cmd flag invalid 0x%04x\n",
++ mmc_resp_type(cmd));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ switch (mmc_cmd_type(cmd)) {
++ case MMC_CMD_BC:
++ cmd_type = GB_SDIO_CMD_BC;
++ break;
++ case MMC_CMD_BCR:
++ cmd_type = GB_SDIO_CMD_BCR;
++ break;
++ case MMC_CMD_AC:
++ cmd_type = GB_SDIO_CMD_AC;
++ break;
++ case MMC_CMD_ADTC:
++ cmd_type = GB_SDIO_CMD_ADTC;
++ break;
++ default:
++ dev_err(mmc_dev(host->mmc), "cmd type invalid 0x%04x\n",
++ mmc_cmd_type(cmd));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ request.cmd = cmd->opcode;
++ request.cmd_flags = cmd_flags;
++ request.cmd_type = cmd_type;
++ request.cmd_arg = cpu_to_le32(cmd->arg);
++ /* some controllers need to know at command time data details */
++ if (data) {
++ request.data_blocks = cpu_to_le16(data->blocks);
++ request.data_blksz = cpu_to_le16(data->blksz);
++ }
++
++ ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_COMMAND,
++ &request, sizeof(request), &response,
++ sizeof(response));
++ if (ret < 0)
++ goto out;
++
++ /* no response expected */
++ if (cmd_flags & GB_SDIO_RSP_NONE)
++ goto out;
++
++ /* long response expected */
++ if (cmd_flags & GB_SDIO_RSP_R2)
++ for (i = 0; i < 4; i++)
++ cmd->resp[i] = le32_to_cpu(response.resp[i]);
++ else
++ cmd->resp[0] = le32_to_cpu(response.resp[0]);
++
++out:
++ cmd->error = ret;
++ return ret;
++}
++
++static void gb_sdio_mrq_work(struct work_struct *work)
++{
++ struct gb_sdio_host *host;
++ struct mmc_request *mrq;
++ int ret;
++
++ host = container_of(work, struct gb_sdio_host, mrqwork);
++
++ ret = gbphy_runtime_get_sync(host->gbphy_dev);
++ if (ret)
++ return;
++
++ mutex_lock(&host->lock);
++ mrq = host->mrq;
++ if (!mrq) {
++ mutex_unlock(&host->lock);
++ gbphy_runtime_put_autosuspend(host->gbphy_dev);
++ dev_err(mmc_dev(host->mmc), "mmc request is NULL");
++ return;
++ }
++
++ if (host->removed) {
++ mrq->cmd->error = -ESHUTDOWN;
++ goto done;
++ }
++
++ if (mrq->sbc) {
++ ret = gb_sdio_command(host, mrq->sbc);
++ if (ret < 0)
++ goto done;
++ }
++
++ ret = gb_sdio_command(host, mrq->cmd);
++ if (ret < 0)
++ goto done;
++
++ if (mrq->data) {
++ ret = gb_sdio_transfer(host, mrq->data);
++ if (ret < 0)
++ goto done;
++ }
++
++ if (mrq->stop) {
++ ret = gb_sdio_command(host, mrq->stop);
++ if (ret < 0)
++ goto done;
++ }
++
++done:
++ host->mrq = NULL;
++ mutex_unlock(&host->lock);
++ mmc_request_done(host->mmc, mrq);
++ gbphy_runtime_put_autosuspend(host->gbphy_dev);
++}
++
++static void gb_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct gb_sdio_host *host = mmc_priv(mmc);
++ struct mmc_command *cmd = mrq->cmd;
++
++ /* Check if it is a cancel to ongoing transfer */
++ if (cmd->opcode == MMC_STOP_TRANSMISSION) {
++ spin_lock(&host->xfer);
++ host->xfer_stop = true;
++ spin_unlock(&host->xfer);
++ }
++
++ mutex_lock(&host->lock);
++
++ WARN_ON(host->mrq);
++ host->mrq = mrq;
++
++ if (host->removed) {
++ mrq->cmd->error = -ESHUTDOWN;
++ goto out;
++ }
++ if (!host->card_present) {
++ mrq->cmd->error = -ENOMEDIUM;
++ goto out;
++ }
++
++ queue_work(host->mrq_workqueue, &host->mrqwork);
++
++ mutex_unlock(&host->lock);
++ return;
++
++out:
++ host->mrq = NULL;
++ mutex_unlock(&host->lock);
++ mmc_request_done(mmc, mrq);
++}
++
++static void gb_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ struct gb_sdio_host *host = mmc_priv(mmc);
++ struct gb_sdio_set_ios_request request;
++ int ret;
++ u8 power_mode;
++ u8 bus_width;
++ u8 timing;
++ u8 signal_voltage;
++ u8 drv_type;
++ u32 vdd = 0;
++
++ mutex_lock(&host->lock);
++ request.clock = cpu_to_le32(ios->clock);
++
++ if (ios->vdd)
++ vdd = 1 << (ios->vdd - GB_SDIO_VDD_SHIFT);
++ request.vdd = cpu_to_le32(vdd);
++
++ request.bus_mode = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN ?
++ GB_SDIO_BUSMODE_OPENDRAIN :
++ GB_SDIO_BUSMODE_PUSHPULL);
++
++ switch (ios->power_mode) {
++ case MMC_POWER_OFF:
++ default:
++ power_mode = GB_SDIO_POWER_OFF;
++ break;
++ case MMC_POWER_UP:
++ power_mode = GB_SDIO_POWER_UP;
++ break;
++ case MMC_POWER_ON:
++ power_mode = GB_SDIO_POWER_ON;
++ break;
++ case MMC_POWER_UNDEFINED:
++ power_mode = GB_SDIO_POWER_UNDEFINED;
++ break;
++ }
++ request.power_mode = power_mode;
++
++ switch (ios->bus_width) {
++ case MMC_BUS_WIDTH_1:
++ bus_width = GB_SDIO_BUS_WIDTH_1;
++ break;
++ case MMC_BUS_WIDTH_4:
++ default:
++ bus_width = GB_SDIO_BUS_WIDTH_4;
++ break;
++ case MMC_BUS_WIDTH_8:
++ bus_width = GB_SDIO_BUS_WIDTH_8;
++ break;
++ }
++ request.bus_width = bus_width;
++
++ switch (ios->timing) {
++ case MMC_TIMING_LEGACY:
++ default:
++ timing = GB_SDIO_TIMING_LEGACY;
++ break;
++ case MMC_TIMING_MMC_HS:
++ timing = GB_SDIO_TIMING_MMC_HS;
++ break;
++ case MMC_TIMING_SD_HS:
++ timing = GB_SDIO_TIMING_SD_HS;
++ break;
++ case MMC_TIMING_UHS_SDR12:
++ timing = GB_SDIO_TIMING_UHS_SDR12;
++ break;
++ case MMC_TIMING_UHS_SDR25:
++ timing = GB_SDIO_TIMING_UHS_SDR25;
++ break;
++ case MMC_TIMING_UHS_SDR50:
++ timing = GB_SDIO_TIMING_UHS_SDR50;
++ break;
++ case MMC_TIMING_UHS_SDR104:
++ timing = GB_SDIO_TIMING_UHS_SDR104;
++ break;
++ case MMC_TIMING_UHS_DDR50:
++ timing = GB_SDIO_TIMING_UHS_DDR50;
++ break;
++ case MMC_TIMING_MMC_DDR52:
++ timing = GB_SDIO_TIMING_MMC_DDR52;
++ break;
++ case MMC_TIMING_MMC_HS200:
++ timing = GB_SDIO_TIMING_MMC_HS200;
++ break;
++ case MMC_TIMING_MMC_HS400:
++ timing = GB_SDIO_TIMING_MMC_HS400;
++ break;
++ }
++ request.timing = timing;
++
++ switch (ios->signal_voltage) {
++ case MMC_SIGNAL_VOLTAGE_330:
++ signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_330;
++ break;
++ case MMC_SIGNAL_VOLTAGE_180:
++ default:
++ signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_180;
++ break;
++ case MMC_SIGNAL_VOLTAGE_120:
++ signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_120;
++ break;
++ }
++ request.signal_voltage = signal_voltage;
++
++ switch (ios->drv_type) {
++ case MMC_SET_DRIVER_TYPE_A:
++ drv_type = GB_SDIO_SET_DRIVER_TYPE_A;
++ break;
++ case MMC_SET_DRIVER_TYPE_C:
++ drv_type = GB_SDIO_SET_DRIVER_TYPE_C;
++ break;
++ case MMC_SET_DRIVER_TYPE_D:
++ drv_type = GB_SDIO_SET_DRIVER_TYPE_D;
++ break;
++ case MMC_SET_DRIVER_TYPE_B:
++ default:
++ drv_type = GB_SDIO_SET_DRIVER_TYPE_B;
++ break;
++ }
++ request.drv_type = drv_type;
++
++ ret = gb_sdio_set_ios(host, &request);
++ if (ret < 0)
++ goto out;
++
++ memcpy(&mmc->ios, ios, sizeof(mmc->ios));
++
++out:
++ mutex_unlock(&host->lock);
++}
++
++static int gb_mmc_get_ro(struct mmc_host *mmc)
++{
++ struct gb_sdio_host *host = mmc_priv(mmc);
++
++ mutex_lock(&host->lock);
++ if (host->removed) {
++ mutex_unlock(&host->lock);
++ return -ESHUTDOWN;
++ }
++ mutex_unlock(&host->lock);
++
++ return host->read_only;
++}
++
++static int gb_mmc_get_cd(struct mmc_host *mmc)
++{
++ struct gb_sdio_host *host = mmc_priv(mmc);
++
++ mutex_lock(&host->lock);
++ if (host->removed) {
++ mutex_unlock(&host->lock);
++ return -ESHUTDOWN;
++ }
++ mutex_unlock(&host->lock);
++
++ return host->card_present;
++}
++
++static int gb_mmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ return 0;
++}
++
++static const struct mmc_host_ops gb_sdio_ops = {
++ .request = gb_mmc_request,
++ .set_ios = gb_mmc_set_ios,
++ .get_ro = gb_mmc_get_ro,
++ .get_cd = gb_mmc_get_cd,
++ .start_signal_voltage_switch = gb_mmc_switch_voltage,
++};
++
++static int gb_sdio_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ struct mmc_host *mmc;
++ struct gb_sdio_host *host;
++ int ret = 0;
++
++ mmc = mmc_alloc_host(sizeof(*host), &gbphy_dev->dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ gb_sdio_request_handler);
++ if (IS_ERR(connection)) {
++ ret = PTR_ERR(connection);
++ goto exit_mmc_free;
++ }
++
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ host->removed = true;
++
++ host->connection = connection;
++ gb_connection_set_data(connection, host);
++ host->gbphy_dev = gbphy_dev;
++ gb_gbphy_set_data(gbphy_dev, host);
++
++ ret = gb_connection_enable_tx(connection);
++ if (ret)
++ goto exit_connection_destroy;
++
++ ret = gb_sdio_get_caps(host);
++ if (ret < 0)
++ goto exit_connection_disable;
++
++ mmc->ops = &gb_sdio_ops;
++
++ mmc->max_segs = host->mmc->max_blk_count;
++
++ /* for now we make a map 1:1 between max request and segment size */
++ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
++ mmc->max_seg_size = mmc->max_req_size;
++
++ mutex_init(&host->lock);
++ spin_lock_init(&host->xfer);
++ host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1,
++ dev_name(&gbphy_dev->dev));
++ if (!host->mrq_workqueue) {
++ ret = -ENOMEM;
++ goto exit_connection_disable;
++ }
++ INIT_WORK(&host->mrqwork, gb_sdio_mrq_work);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto exit_wq_destroy;
++
++ ret = mmc_add_host(mmc);
++ if (ret < 0)
++ goto exit_wq_destroy;
++ host->removed = false;
++ ret = _gb_sdio_process_events(host, host->queued_events);
++ host->queued_events = 0;
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++
++ return ret;
++
++exit_wq_destroy:
++ destroy_workqueue(host->mrq_workqueue);
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_mmc_free:
++ mmc_free_host(mmc);
++
++ return ret;
++}
++
++static void gb_sdio_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_sdio_host *host = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = host->connection;
++ struct mmc_host *mmc;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ mutex_lock(&host->lock);
++ host->removed = true;
++ mmc = host->mmc;
++ gb_connection_set_data(connection, NULL);
++ mutex_unlock(&host->lock);
++
++ flush_workqueue(host->mrq_workqueue);
++ destroy_workqueue(host->mrq_workqueue);
++ gb_connection_disable_rx(connection);
++ mmc_remove_host(mmc);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++ mmc_free_host(mmc);
++}
++
++static const struct gbphy_device_id gb_sdio_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_SDIO) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_sdio_id_table);
++
++static struct gbphy_driver sdio_driver = {
++ .name = "sdio",
++ .probe = gb_sdio_probe,
++ .remove = gb_sdio_remove,
++ .id_table = gb_sdio_id_table,
++};
++
++module_gbphy_driver(sdio_driver);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_spi.patch b/greybus_spi.patch
new file mode 100644
index 00000000000000..eb7cd8f578b5d8
--- /dev/null
+++ b/greybus_spi.patch
@@ -0,0 +1,683 @@
+---
+ drivers/greybus/spi.c | 79 ++++++
+ drivers/greybus/spilib.c | 565 +++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/spilib.h | 24 +
+ 3 files changed, 668 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/spi.c
+@@ -0,0 +1,79 @@
++/*
++ * SPI bridge PHY driver.
++ *
++ * Copyright 2014-2016 Google Inc.
++ * Copyright 2014-2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/module.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++#include "spilib.h"
++
++static struct spilib_ops *spilib_ops;
++
++static int gb_spi_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ int ret;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ NULL);
++ if (IS_ERR(connection))
++ return PTR_ERR(connection);
++
++ ret = gb_connection_enable(connection);
++ if (ret)
++ goto exit_connection_destroy;
++
++ ret = gb_spilib_master_init(connection, &gbphy_dev->dev, spilib_ops);
++ if (ret)
++ goto exit_connection_disable;
++
++ gb_gbphy_set_data(gbphy_dev, connection);
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return 0;
++
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++
++ return ret;
++}
++
++static void gb_spi_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_connection *connection = gb_gbphy_get_data(gbphy_dev);
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ gb_spilib_master_exit(connection);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++}
++
++static const struct gbphy_device_id gb_spi_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_SPI) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_spi_id_table);
++
++static struct gbphy_driver spi_driver = {
++ .name = "spi",
++ .probe = gb_spi_probe,
++ .remove = gb_spi_remove,
++ .id_table = gb_spi_id_table,
++};
++
++module_gbphy_driver(spi_driver);
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/greybus/spilib.c
+@@ -0,0 +1,565 @@
++/*
++ * Greybus SPI library
++ *
++ * Copyright 2014-2016 Google Inc.
++ * Copyright 2014-2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/bitops.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/spi/spi.h>
++
++#include "greybus.h"
++#include "spilib.h"
++
++struct gb_spilib {
++ struct gb_connection *connection;
++ struct device *parent;
++ struct spi_transfer *first_xfer;
++ struct spi_transfer *last_xfer;
++ struct spilib_ops *ops;
++ u32 rx_xfer_offset;
++ u32 tx_xfer_offset;
++ u32 last_xfer_size;
++ unsigned int op_timeout;
++ u16 mode;
++ u16 flags;
++ u32 bits_per_word_mask;
++ u8 num_chipselect;
++ u32 min_speed_hz;
++ u32 max_speed_hz;
++};
++
++#define GB_SPI_STATE_MSG_DONE ((void *)0)
++#define GB_SPI_STATE_MSG_IDLE ((void *)1)
++#define GB_SPI_STATE_MSG_RUNNING ((void *)2)
++#define GB_SPI_STATE_OP_READY ((void *)3)
++#define GB_SPI_STATE_OP_DONE ((void *)4)
++#define GB_SPI_STATE_MSG_ERROR ((void *)-1)
++
++#define XFER_TIMEOUT_TOLERANCE 200
++
++static struct spi_master *get_master_from_spi(struct gb_spilib *spi)
++{
++ return gb_connection_get_data(spi->connection);
++}
++
++static int tx_header_fit_operation(u32 tx_size, u32 count, size_t data_max)
++{
++ size_t headers_size;
++
++ data_max -= sizeof(struct gb_spi_transfer_request);
++ headers_size = (count + 1) * sizeof(struct gb_spi_transfer);
++
++ return tx_size + headers_size > data_max ? 0 : 1;
++}
++
++static size_t calc_rx_xfer_size(u32 rx_size, u32 *tx_xfer_size, u32 len,
++ size_t data_max)
++{
++ size_t rx_xfer_size;
++
++ data_max -= sizeof(struct gb_spi_transfer_response);
++
++ if (rx_size + len > data_max)
++ rx_xfer_size = data_max - rx_size;
++ else
++ rx_xfer_size = len;
++
++ /* if this is a write_read, for symmetry read the same as write */
++ if (*tx_xfer_size && rx_xfer_size > *tx_xfer_size)
++ rx_xfer_size = *tx_xfer_size;
++ if (*tx_xfer_size && rx_xfer_size < *tx_xfer_size)
++ *tx_xfer_size = rx_xfer_size;
++
++ return rx_xfer_size;
++}
++
++static size_t calc_tx_xfer_size(u32 tx_size, u32 count, size_t len,
++ size_t data_max)
++{
++ size_t headers_size;
++
++ data_max -= sizeof(struct gb_spi_transfer_request);
++ headers_size = (count + 1) * sizeof(struct gb_spi_transfer);
++
++ if (tx_size + headers_size + len > data_max)
++ return data_max - (tx_size + sizeof(struct gb_spi_transfer));
++
++ return len;
++}
++
++static void clean_xfer_state(struct gb_spilib *spi)
++{
++ spi->first_xfer = NULL;
++ spi->last_xfer = NULL;
++ spi->rx_xfer_offset = 0;
++ spi->tx_xfer_offset = 0;
++ spi->last_xfer_size = 0;
++ spi->op_timeout = 0;
++}
++
++static bool is_last_xfer_done(struct gb_spilib *spi)
++{
++ struct spi_transfer *last_xfer = spi->last_xfer;
++
++ if ((spi->tx_xfer_offset + spi->last_xfer_size == last_xfer->len) ||
++ (spi->rx_xfer_offset + spi->last_xfer_size == last_xfer->len))
++ return true;
++
++ return false;
++}
++
++static int setup_next_xfer(struct gb_spilib *spi, struct spi_message *msg)
++{
++ struct spi_transfer *last_xfer = spi->last_xfer;
++
++ if (msg->state != GB_SPI_STATE_OP_DONE)
++ return 0;
++
++ /*
++ * if we transferred all content of the last transfer, reset values and
++ * check if this was the last transfer in the message
++ */
++ if (is_last_xfer_done(spi)) {
++ spi->tx_xfer_offset = 0;
++ spi->rx_xfer_offset = 0;
++ spi->op_timeout = 0;
++ if (last_xfer == list_last_entry(&msg->transfers,
++ struct spi_transfer,
++ transfer_list))
++ msg->state = GB_SPI_STATE_MSG_DONE;
++ else
++ spi->first_xfer = list_next_entry(last_xfer,
++ transfer_list);
++ return 0;
++ }
++
++ spi->first_xfer = last_xfer;
++ if (last_xfer->tx_buf)
++ spi->tx_xfer_offset += spi->last_xfer_size;
++
++ if (last_xfer->rx_buf)
++ spi->rx_xfer_offset += spi->last_xfer_size;
++
++ return 0;
++}
++
++static struct spi_transfer *get_next_xfer(struct spi_transfer *xfer,
++ struct spi_message *msg)
++{
++ if (xfer == list_last_entry(&msg->transfers, struct spi_transfer,
++ transfer_list))
++ return NULL;
++
++ return list_next_entry(xfer, transfer_list);
++}
++
++/* Routines to transfer data */
++static struct gb_operation *gb_spi_operation_create(struct gb_spilib *spi,
++ struct gb_connection *connection, struct spi_message *msg)
++{
++ struct gb_spi_transfer_request *request;
++ struct spi_device *dev = msg->spi;
++ struct spi_transfer *xfer;
++ struct gb_spi_transfer *gb_xfer;
++ struct gb_operation *operation;
++ u32 tx_size = 0, rx_size = 0, count = 0, xfer_len = 0, request_size;
++ u32 tx_xfer_size = 0, rx_xfer_size = 0, len;
++ u32 total_len = 0;
++ unsigned int xfer_timeout;
++ size_t data_max;
++ void *tx_data;
++
++ data_max = gb_operation_get_payload_size_max(connection);
++ xfer = spi->first_xfer;
++
++ /* Find number of transfers queued and tx/rx length in the message */
++
++ while (msg->state != GB_SPI_STATE_OP_READY) {
++ msg->state = GB_SPI_STATE_MSG_RUNNING;
++ spi->last_xfer = xfer;
++
++ if (!xfer->tx_buf && !xfer->rx_buf) {
++ dev_err(spi->parent,
++ "bufferless transfer, length %u\n", xfer->len);
++ msg->state = GB_SPI_STATE_MSG_ERROR;
++ return NULL;
++ }
++
++ tx_xfer_size = 0;
++ rx_xfer_size = 0;
++
++ if (xfer->tx_buf) {
++ len = xfer->len - spi->tx_xfer_offset;
++ if (!tx_header_fit_operation(tx_size, count, data_max))
++ break;
++ tx_xfer_size = calc_tx_xfer_size(tx_size, count,
++ len, data_max);
++ spi->last_xfer_size = tx_xfer_size;
++ }
++
++ if (xfer->rx_buf) {
++ len = xfer->len - spi->rx_xfer_offset;
++ rx_xfer_size = calc_rx_xfer_size(rx_size, &tx_xfer_size,
++ len, data_max);
++ spi->last_xfer_size = rx_xfer_size;
++ }
++
++ tx_size += tx_xfer_size;
++ rx_size += rx_xfer_size;
++
++ total_len += spi->last_xfer_size;
++ count++;
++
++ xfer = get_next_xfer(xfer, msg);
++ if (!xfer || total_len >= data_max)
++ msg->state = GB_SPI_STATE_OP_READY;
++ }
++
++ /*
++ * In addition to space for all message descriptors we need
++ * to have enough to hold all tx data.
++ */
++ request_size = sizeof(*request);
++ request_size += count * sizeof(*gb_xfer);
++ request_size += tx_size;
++
++ /* Response consists only of incoming data */
++ operation = gb_operation_create(connection, GB_SPI_TYPE_TRANSFER,
++ request_size, rx_size, GFP_KERNEL);
++ if (!operation)
++ return NULL;
++
++ request = operation->request->payload;
++ request->count = cpu_to_le16(count);
++ request->mode = dev->mode;
++ request->chip_select = dev->chip_select;
++
++ gb_xfer = &request->transfers[0];
++ tx_data = gb_xfer + count; /* place tx data after last gb_xfer */
++
++ /* Fill in the transfers array */
++ xfer = spi->first_xfer;
++ while (msg->state != GB_SPI_STATE_OP_DONE) {
++ if (xfer == spi->last_xfer)
++ xfer_len = spi->last_xfer_size;
++ else
++ xfer_len = xfer->len;
++
++ /* make sure we do not timeout in a slow transfer */
++ xfer_timeout = xfer_len * 8 * MSEC_PER_SEC / xfer->speed_hz;
++ xfer_timeout += GB_OPERATION_TIMEOUT_DEFAULT;
++
++ if (xfer_timeout > spi->op_timeout)
++ spi->op_timeout = xfer_timeout;
++
++ gb_xfer->speed_hz = cpu_to_le32(xfer->speed_hz);
++ gb_xfer->len = cpu_to_le32(xfer_len);
++ gb_xfer->delay_usecs = cpu_to_le16(xfer->delay_usecs);
++ gb_xfer->cs_change = xfer->cs_change;
++ gb_xfer->bits_per_word = xfer->bits_per_word;
++
++ /* Copy tx data */
++ if (xfer->tx_buf) {
++ gb_xfer->xfer_flags |= GB_SPI_XFER_WRITE;
++ memcpy(tx_data, xfer->tx_buf + spi->tx_xfer_offset,
++ xfer_len);
++ tx_data += xfer_len;
++ }
++
++ if (xfer->rx_buf)
++ gb_xfer->xfer_flags |= GB_SPI_XFER_READ;
++
++ if (xfer == spi->last_xfer) {
++ if (!is_last_xfer_done(spi))
++ gb_xfer->xfer_flags |= GB_SPI_XFER_INPROGRESS;
++ msg->state = GB_SPI_STATE_OP_DONE;
++ continue;
++ }
++
++ gb_xfer++;
++ xfer = get_next_xfer(xfer, msg);
++ }
++
++ msg->actual_length += total_len;
++
++ return operation;
++}
++
++static void gb_spi_decode_response(struct gb_spilib *spi,
++ struct spi_message *msg,
++ struct gb_spi_transfer_response *response)
++{
++ struct spi_transfer *xfer = spi->first_xfer;
++ void *rx_data = response->data;
++ u32 xfer_len;
++
++ while (xfer) {
++ /* Copy rx data */
++ if (xfer->rx_buf) {
++ if (xfer == spi->first_xfer)
++ xfer_len = xfer->len - spi->rx_xfer_offset;
++ else if (xfer == spi->last_xfer)
++ xfer_len = spi->last_xfer_size;
++ else
++ xfer_len = xfer->len;
++
++ memcpy(xfer->rx_buf + spi->rx_xfer_offset, rx_data,
++ xfer_len);
++ rx_data += xfer_len;
++ }
++
++ if (xfer == spi->last_xfer)
++ break;
++
++ xfer = list_next_entry(xfer, transfer_list);
++ }
++}
++
++static int gb_spi_transfer_one_message(struct spi_master *master,
++ struct spi_message *msg)
++{
++ struct gb_spilib *spi = spi_master_get_devdata(master);
++ struct gb_connection *connection = spi->connection;
++ struct gb_spi_transfer_response *response;
++ struct gb_operation *operation;
++ int ret = 0;
++
++ spi->first_xfer = list_first_entry_or_null(&msg->transfers,
++ struct spi_transfer,
++ transfer_list);
++ if (!spi->first_xfer) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ msg->state = GB_SPI_STATE_MSG_IDLE;
++
++ while (msg->state != GB_SPI_STATE_MSG_DONE &&
++ msg->state != GB_SPI_STATE_MSG_ERROR) {
++ operation = gb_spi_operation_create(spi, connection, msg);
++ if (!operation) {
++ msg->state = GB_SPI_STATE_MSG_ERROR;
++ ret = -EINVAL;
++ continue;
++ }
++
++ ret = gb_operation_request_send_sync_timeout(operation,
++ spi->op_timeout);
++ if (!ret) {
++ response = operation->response->payload;
++ if (response)
++ gb_spi_decode_response(spi, msg, response);
++ } else {
++ dev_err(spi->parent,
++ "transfer operation failed: %d\n", ret);
++ msg->state = GB_SPI_STATE_MSG_ERROR;
++ }
++
++ gb_operation_put(operation);
++ setup_next_xfer(spi, msg);
++ }
++
++out:
++ msg->status = ret;
++ clean_xfer_state(spi);
++ spi_finalize_current_message(master);
++
++ return ret;
++}
++
++static int gb_spi_prepare_transfer_hardware(struct spi_master *master)
++{
++ struct gb_spilib *spi = spi_master_get_devdata(master);
++
++ return spi->ops->prepare_transfer_hardware(spi->parent);
++}
++
++static int gb_spi_unprepare_transfer_hardware(struct spi_master *master)
++{
++ struct gb_spilib *spi = spi_master_get_devdata(master);
++
++ spi->ops->unprepare_transfer_hardware(spi->parent);
++
++ return 0;
++}
++
++static int gb_spi_setup(struct spi_device *spi)
++{
++ /* Nothing to do for now */
++ return 0;
++}
++
++static void gb_spi_cleanup(struct spi_device *spi)
++{
++ /* Nothing to do for now */
++}
++
++/* Routines to get controller information */
++
++/*
++ * Map Greybus spi mode bits/flags/bpw into Linux ones.
++ * All bits are same for now and so these macro's return same values.
++ */
++#define gb_spi_mode_map(mode) mode
++#define gb_spi_flags_map(flags) flags
++
++static int gb_spi_get_master_config(struct gb_spilib *spi)
++{
++ struct gb_spi_master_config_response response;
++ u16 mode, flags;
++ int ret;
++
++ ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_MASTER_CONFIG,
++ NULL, 0, &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++
++ mode = le16_to_cpu(response.mode);
++ spi->mode = gb_spi_mode_map(mode);
++
++ flags = le16_to_cpu(response.flags);
++ spi->flags = gb_spi_flags_map(flags);
++
++ spi->bits_per_word_mask = le32_to_cpu(response.bits_per_word_mask);
++ spi->num_chipselect = response.num_chipselect;
++
++ spi->min_speed_hz = le32_to_cpu(response.min_speed_hz);
++ spi->max_speed_hz = le32_to_cpu(response.max_speed_hz);
++
++ return 0;
++}
++
++static int gb_spi_setup_device(struct gb_spilib *spi, u8 cs)
++{
++ struct spi_master *master = get_master_from_spi(spi);
++ struct gb_spi_device_config_request request;
++ struct gb_spi_device_config_response response;
++ struct spi_board_info spi_board = { {0} };
++ struct spi_device *spidev;
++ int ret;
++ u8 dev_type;
++
++ request.chip_select = cs;
++
++ ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_DEVICE_CONFIG,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++
++ dev_type = response.device_type;
++
++ if (dev_type == GB_SPI_SPI_DEV)
++ strlcpy(spi_board.modalias, "spidev",
++ sizeof(spi_board.modalias));
++ else if (dev_type == GB_SPI_SPI_NOR)
++ strlcpy(spi_board.modalias, "spi-nor",
++ sizeof(spi_board.modalias));
++ else if (dev_type == GB_SPI_SPI_MODALIAS)
++ memcpy(spi_board.modalias, response.name,
++ sizeof(spi_board.modalias));
++ else
++ return -EINVAL;
++
++ spi_board.mode = le16_to_cpu(response.mode);
++ spi_board.bus_num = master->bus_num;
++ spi_board.chip_select = cs;
++ spi_board.max_speed_hz = le32_to_cpu(response.max_speed_hz);
++
++ spidev = spi_new_device(master, &spi_board);
++ if (!spidev)
++ return -EINVAL;
++
++ return 0;
++}
++
++int gb_spilib_master_init(struct gb_connection *connection, struct device *dev,
++ struct spilib_ops *ops)
++{
++ struct gb_spilib *spi;
++ struct spi_master *master;
++ int ret;
++ u8 i;
++
++ /* Allocate master with space for data */
++ master = spi_alloc_master(dev, sizeof(*spi));
++ if (!master) {
++ dev_err(dev, "cannot alloc SPI master\n");
++ return -ENOMEM;
++ }
++
++ spi = spi_master_get_devdata(master);
++ spi->connection = connection;
++ gb_connection_set_data(connection, master);
++ spi->parent = dev;
++ spi->ops = ops;
++
++ /* get master configuration */
++ ret = gb_spi_get_master_config(spi);
++ if (ret)
++ goto exit_spi_put;
++
++ master->bus_num = -1; /* Allow spi-core to allocate it dynamically */
++ master->num_chipselect = spi->num_chipselect;
++ master->mode_bits = spi->mode;
++ master->flags = spi->flags;
++ master->bits_per_word_mask = spi->bits_per_word_mask;
++
++ /* Attach methods */
++ master->cleanup = gb_spi_cleanup;
++ master->setup = gb_spi_setup;
++ master->transfer_one_message = gb_spi_transfer_one_message;
++
++ if (ops && ops->prepare_transfer_hardware) {
++ master->prepare_transfer_hardware =
++ gb_spi_prepare_transfer_hardware;
++ }
++
++ if (ops && ops->unprepare_transfer_hardware) {
++ master->unprepare_transfer_hardware =
++ gb_spi_unprepare_transfer_hardware;
++ }
++
++ master->auto_runtime_pm = true;
++
++ ret = spi_register_master(master);
++ if (ret < 0)
++ goto exit_spi_put;
++
++ /* now, fetch the devices configuration */
++ for (i = 0; i < spi->num_chipselect; i++) {
++ ret = gb_spi_setup_device(spi, i);
++ if (ret < 0) {
++ dev_err(dev, "failed to allocate spi device %d: %d\n",
++ i, ret);
++ goto exit_spi_unregister;
++ }
++ }
++
++ return 0;
++
++exit_spi_unregister:
++ spi_unregister_master(master);
++exit_spi_put:
++ spi_master_put(master);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_spilib_master_init);
++
++void gb_spilib_master_exit(struct gb_connection *connection)
++{
++ struct spi_master *master = gb_connection_get_data(connection);
++
++ spi_unregister_master(master);
++ spi_master_put(master);
++}
++EXPORT_SYMBOL_GPL(gb_spilib_master_exit);
++
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/greybus/spilib.h
+@@ -0,0 +1,24 @@
++/*
++ * Greybus SPI library header
++ *
++ * copyright 2016 google inc.
++ * copyright 2016 linaro ltd.
++ *
++ * released under the gplv2 only.
++ */
++
++#ifndef __SPILIB_H
++#define __SPILIB_H
++
++struct device;
++struct gb_connection;
++
++struct spilib_ops {
++ int (*prepare_transfer_hardware)(struct device *dev);
++ void (*unprepare_transfer_hardware)(struct device *dev);
++};
++
++int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, struct spilib_ops *ops);
++void gb_spilib_master_exit(struct gb_connection *connection);
++
++#endif /* __SPILIB_H */
diff --git a/greybus_svc.patch b/greybus_svc.patch
new file mode 100644
index 00000000000000..388adcc6737733
--- /dev/null
+++ b/greybus_svc.patch
@@ -0,0 +1,1808 @@
+---
+ drivers/greybus/svc.c | 1486 +++++++++++++++++++++++++++++++++++++++++
+ drivers/greybus/svc.h | 109 +++
+ drivers/greybus/svc_watchdog.c | 198 +++++
+ 3 files changed, 1793 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/svc.c
+@@ -0,0 +1,1486 @@
++/*
++ * SVC Greybus driver.
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/debugfs.h>
++#include <linux/workqueue.h>
++
++#include "greybus.h"
++
++#define SVC_INTF_EJECT_TIMEOUT 9000
++#define SVC_INTF_ACTIVATE_TIMEOUT 6000
++#define SVC_INTF_RESUME_TIMEOUT 3000
++
++struct gb_svc_deferred_request {
++ struct work_struct work;
++ struct gb_operation *operation;
++};
++
++
++static int gb_svc_queue_deferred_request(struct gb_operation *operation);
++
++static ssize_t endo_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ return sprintf(buf, "0x%04x\n", svc->endo_id);
++}
++static DEVICE_ATTR_RO(endo_id);
++
++static ssize_t ap_intf_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ return sprintf(buf, "%u\n", svc->ap_intf_id);
++}
++static DEVICE_ATTR_RO(ap_intf_id);
++
++// FIXME
++// This is a hack, we need to do this "right" and clean the interface up
++// properly, not just forcibly yank the thing out of the system and hope for the
++// best. But for now, people want their modules to come out without having to
++// throw the thing to the ground or get out a screwdriver.
++static ssize_t intf_eject_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t len)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++ unsigned short intf_id;
++ int ret;
++
++ ret = kstrtou16(buf, 10, &intf_id);
++ if (ret < 0)
++ return ret;
++
++ dev_warn(dev, "Forcibly trying to eject interface %d\n", intf_id);
++
++ ret = gb_svc_intf_eject(svc, intf_id);
++ if (ret < 0)
++ return ret;
++
++ return len;
++}
++static DEVICE_ATTR_WO(intf_eject);
++
++static ssize_t watchdog_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ return sprintf(buf, "%s\n",
++ gb_svc_watchdog_enabled(svc) ? "enabled" : "disabled");
++}
++
++static ssize_t watchdog_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t len)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++ int retval;
++ bool user_request;
++
++ retval = strtobool(buf, &user_request);
++ if (retval)
++ return retval;
++
++ if (user_request)
++ retval = gb_svc_watchdog_enable(svc);
++ else
++ retval = gb_svc_watchdog_disable(svc);
++ if (retval)
++ return retval;
++ return len;
++}
++static DEVICE_ATTR_RW(watchdog);
++
++static ssize_t watchdog_action_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL)
++ return sprintf(buf, "panic\n");
++ else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO)
++ return sprintf(buf, "reset\n");
++
++ return -EINVAL;
++}
++
++static ssize_t watchdog_action_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ if (sysfs_streq(buf, "panic"))
++ svc->action = GB_SVC_WATCHDOG_BITE_PANIC_KERNEL;
++ else if (sysfs_streq(buf, "reset"))
++ svc->action = GB_SVC_WATCHDOG_BITE_RESET_UNIPRO;
++ else
++ return -EINVAL;
++
++ return len;
++}
++static DEVICE_ATTR_RW(watchdog_action);
++
++static int gb_svc_pwrmon_rail_count_get(struct gb_svc *svc, u8 *value)
++{
++ struct gb_svc_pwrmon_rail_count_get_response response;
++ int ret;
++
++ ret = gb_operation_sync(svc->connection,
++ GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET, NULL, 0,
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&svc->dev, "failed to get rail count: %d\n", ret);
++ return ret;
++ }
++
++ *value = response.rail_count;
++
++ return 0;
++}
++
++static int gb_svc_pwrmon_rail_names_get(struct gb_svc *svc,
++ struct gb_svc_pwrmon_rail_names_get_response *response,
++ size_t bufsize)
++{
++ int ret;
++
++ ret = gb_operation_sync(svc->connection,
++ GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET, NULL, 0,
++ response, bufsize);
++ if (ret) {
++ dev_err(&svc->dev, "failed to get rail names: %d\n", ret);
++ return ret;
++ }
++
++ if (response->status != GB_SVC_OP_SUCCESS) {
++ dev_err(&svc->dev,
++ "SVC error while getting rail names: %u\n",
++ response->status);
++ return -EREMOTEIO;
++ }
++
++ return 0;
++}
++
++static int gb_svc_pwrmon_sample_get(struct gb_svc *svc, u8 rail_id,
++ u8 measurement_type, u32 *value)
++{
++ struct gb_svc_pwrmon_sample_get_request request;
++ struct gb_svc_pwrmon_sample_get_response response;
++ int ret;
++
++ request.rail_id = rail_id;
++ request.measurement_type = measurement_type;
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_PWRMON_SAMPLE_GET,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&svc->dev, "failed to get rail sample: %d\n", ret);
++ return ret;
++ }
++
++ if (response.result) {
++ dev_err(&svc->dev,
++ "UniPro error while getting rail power sample (%d %d): %d\n",
++ rail_id, measurement_type, response.result);
++ switch (response.result) {
++ case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
++ return -EINVAL;
++ case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
++ return -ENOMSG;
++ default:
++ return -EREMOTEIO;
++ }
++ }
++
++ *value = le32_to_cpu(response.measurement);
++
++ return 0;
++}
++
++int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
++ u8 measurement_type, u32 *value)
++{
++ struct gb_svc_pwrmon_intf_sample_get_request request;
++ struct gb_svc_pwrmon_intf_sample_get_response response;
++ int ret;
++
++ request.intf_id = intf_id;
++ request.measurement_type = measurement_type;
++
++ ret = gb_operation_sync(svc->connection,
++ GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&svc->dev, "failed to get intf sample: %d\n", ret);
++ return ret;
++ }
++
++ if (response.result) {
++ dev_err(&svc->dev,
++ "UniPro error while getting intf power sample (%d %d): %d\n",
++ intf_id, measurement_type, response.result);
++ switch (response.result) {
++ case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
++ return -EINVAL;
++ case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
++ return -ENOMSG;
++ default:
++ return -EREMOTEIO;
++ }
++ }
++
++ *value = le32_to_cpu(response.measurement);
++
++ return 0;
++}
++
++static struct attribute *svc_attrs[] = {
++ &dev_attr_endo_id.attr,
++ &dev_attr_ap_intf_id.attr,
++ &dev_attr_intf_eject.attr,
++ &dev_attr_watchdog.attr,
++ &dev_attr_watchdog_action.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(svc);
++
++int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
++{
++ struct gb_svc_intf_device_id_request request;
++
++ request.intf_id = intf_id;
++ request.device_id = device_id;
++
++ return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
++ &request, sizeof(request), NULL, 0);
++}
++
++int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id)
++{
++ struct gb_svc_intf_eject_request request;
++ int ret;
++
++ request.intf_id = intf_id;
++
++ /*
++ * The pulse width for module release in svc is long so we need to
++ * increase the timeout so the operation will not return to soon.
++ */
++ ret = gb_operation_sync_timeout(svc->connection,
++ GB_SVC_TYPE_INTF_EJECT, &request,
++ sizeof(request), NULL, 0,
++ SVC_INTF_EJECT_TIMEOUT);
++ if (ret) {
++ dev_err(&svc->dev, "failed to eject interface %u\n", intf_id);
++ return ret;
++ }
++
++ return 0;
++}
++
++int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable)
++{
++ struct gb_svc_intf_vsys_request request;
++ struct gb_svc_intf_vsys_response response;
++ int type, ret;
++
++ request.intf_id = intf_id;
++
++ if (enable)
++ type = GB_SVC_TYPE_INTF_VSYS_ENABLE;
++ else
++ type = GB_SVC_TYPE_INTF_VSYS_DISABLE;
++
++ ret = gb_operation_sync(svc->connection, type,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++ if (response.result_code != GB_SVC_INTF_VSYS_OK)
++ return -EREMOTEIO;
++ return 0;
++}
++
++int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable)
++{
++ struct gb_svc_intf_refclk_request request;
++ struct gb_svc_intf_refclk_response response;
++ int type, ret;
++
++ request.intf_id = intf_id;
++
++ if (enable)
++ type = GB_SVC_TYPE_INTF_REFCLK_ENABLE;
++ else
++ type = GB_SVC_TYPE_INTF_REFCLK_DISABLE;
++
++ ret = gb_operation_sync(svc->connection, type,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++ if (response.result_code != GB_SVC_INTF_REFCLK_OK)
++ return -EREMOTEIO;
++ return 0;
++}
++
++int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable)
++{
++ struct gb_svc_intf_unipro_request request;
++ struct gb_svc_intf_unipro_response response;
++ int type, ret;
++
++ request.intf_id = intf_id;
++
++ if (enable)
++ type = GB_SVC_TYPE_INTF_UNIPRO_ENABLE;
++ else
++ type = GB_SVC_TYPE_INTF_UNIPRO_DISABLE;
++
++ ret = gb_operation_sync(svc->connection, type,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++ if (response.result_code != GB_SVC_INTF_UNIPRO_OK)
++ return -EREMOTEIO;
++ return 0;
++}
++
++int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type)
++{
++ struct gb_svc_intf_activate_request request;
++ struct gb_svc_intf_activate_response response;
++ int ret;
++
++ request.intf_id = intf_id;
++
++ ret = gb_operation_sync_timeout(svc->connection,
++ GB_SVC_TYPE_INTF_ACTIVATE,
++ &request, sizeof(request),
++ &response, sizeof(response),
++ SVC_INTF_ACTIVATE_TIMEOUT);
++ if (ret < 0)
++ return ret;
++ if (response.status != GB_SVC_OP_SUCCESS) {
++ dev_err(&svc->dev, "failed to activate interface %u: %u\n",
++ intf_id, response.status);
++ return -EREMOTEIO;
++ }
++
++ *intf_type = response.intf_type;
++
++ return 0;
++}
++
++int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id)
++{
++ struct gb_svc_intf_resume_request request;
++ struct gb_svc_intf_resume_response response;
++ int ret;
++
++ request.intf_id = intf_id;
++
++ ret = gb_operation_sync_timeout(svc->connection,
++ GB_SVC_TYPE_INTF_RESUME,
++ &request, sizeof(request),
++ &response, sizeof(response),
++ SVC_INTF_RESUME_TIMEOUT);
++ if (ret < 0) {
++ dev_err(&svc->dev, "failed to send interface resume %u: %d\n",
++ intf_id, ret);
++ return ret;
++ }
++
++ if (response.status != GB_SVC_OP_SUCCESS) {
++ dev_err(&svc->dev, "failed to resume interface %u: %u\n",
++ intf_id, response.status);
++ return -EREMOTEIO;
++ }
++
++ return 0;
++}
++
++int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
++ u32 *value)
++{
++ struct gb_svc_dme_peer_get_request request;
++ struct gb_svc_dme_peer_get_response response;
++ u16 result;
++ int ret;
++
++ request.intf_id = intf_id;
++ request.attr = cpu_to_le16(attr);
++ request.selector = cpu_to_le16(selector);
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_GET,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&svc->dev, "failed to get DME attribute (%u 0x%04x %u): %d\n",
++ intf_id, attr, selector, ret);
++ return ret;
++ }
++
++ result = le16_to_cpu(response.result_code);
++ if (result) {
++ dev_err(&svc->dev, "UniPro error while getting DME attribute (%u 0x%04x %u): %u\n",
++ intf_id, attr, selector, result);
++ return -EREMOTEIO;
++ }
++
++ if (value)
++ *value = le32_to_cpu(response.attr_value);
++
++ return 0;
++}
++
++int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
++ u32 value)
++{
++ struct gb_svc_dme_peer_set_request request;
++ struct gb_svc_dme_peer_set_response response;
++ u16 result;
++ int ret;
++
++ request.intf_id = intf_id;
++ request.attr = cpu_to_le16(attr);
++ request.selector = cpu_to_le16(selector);
++ request.value = cpu_to_le32(value);
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_SET,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret) {
++ dev_err(&svc->dev, "failed to set DME attribute (%u 0x%04x %u %u): %d\n",
++ intf_id, attr, selector, value, ret);
++ return ret;
++ }
++
++ result = le16_to_cpu(response.result_code);
++ if (result) {
++ dev_err(&svc->dev, "UniPro error while setting DME attribute (%u 0x%04x %u %u): %u\n",
++ intf_id, attr, selector, value, result);
++ return -EREMOTEIO;
++ }
++
++ return 0;
++}
++
++int gb_svc_connection_create(struct gb_svc *svc,
++ u8 intf1_id, u16 cport1_id,
++ u8 intf2_id, u16 cport2_id,
++ u8 cport_flags)
++{
++ struct gb_svc_conn_create_request request;
++
++ request.intf1_id = intf1_id;
++ request.cport1_id = cpu_to_le16(cport1_id);
++ request.intf2_id = intf2_id;
++ request.cport2_id = cpu_to_le16(cport2_id);
++ request.tc = 0; /* TC0 */
++ request.flags = cport_flags;
++
++ return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
++ &request, sizeof(request), NULL, 0);
++}
++
++void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
++ u8 intf2_id, u16 cport2_id)
++{
++ struct gb_svc_conn_destroy_request request;
++ struct gb_connection *connection = svc->connection;
++ int ret;
++
++ request.intf1_id = intf1_id;
++ request.cport1_id = cpu_to_le16(cport1_id);
++ request.intf2_id = intf2_id;
++ request.cport2_id = cpu_to_le16(cport2_id);
++
++ ret = gb_operation_sync(connection, GB_SVC_TYPE_CONN_DESTROY,
++ &request, sizeof(request), NULL, 0);
++ if (ret) {
++ dev_err(&svc->dev, "failed to destroy connection (%u:%u %u:%u): %d\n",
++ intf1_id, cport1_id, intf2_id, cport2_id, ret);
++ }
++}
++
++int gb_svc_timesync_enable(struct gb_svc *svc, u8 count, u64 frame_time,
++ u32 strobe_delay, u32 refclk)
++{
++ struct gb_connection *connection = svc->connection;
++ struct gb_svc_timesync_enable_request request;
++
++ request.count = count;
++ request.frame_time = cpu_to_le64(frame_time);
++ request.strobe_delay = cpu_to_le32(strobe_delay);
++ request.refclk = cpu_to_le32(refclk);
++ return gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_ENABLE,
++ &request, sizeof(request), NULL, 0);
++}
++
++int gb_svc_timesync_disable(struct gb_svc *svc)
++{
++ struct gb_connection *connection = svc->connection;
++
++ return gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_DISABLE,
++ NULL, 0, NULL, 0);
++}
++
++int gb_svc_timesync_authoritative(struct gb_svc *svc, u64 *frame_time)
++{
++ struct gb_connection *connection = svc->connection;
++ struct gb_svc_timesync_authoritative_response response;
++ int ret, i;
++
++ ret = gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_AUTHORITATIVE, NULL, 0,
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++
++ for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
++ frame_time[i] = le64_to_cpu(response.frame_time[i]);
++ return 0;
++}
++
++int gb_svc_timesync_ping(struct gb_svc *svc, u64 *frame_time)
++{
++ struct gb_connection *connection = svc->connection;
++ struct gb_svc_timesync_ping_response response;
++ int ret;
++
++ ret = gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_PING,
++ NULL, 0,
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++
++ *frame_time = le64_to_cpu(response.frame_time);
++ return 0;
++}
++
++int gb_svc_timesync_wake_pins_acquire(struct gb_svc *svc, u32 strobe_mask)
++{
++ struct gb_connection *connection = svc->connection;
++ struct gb_svc_timesync_wake_pins_acquire_request request;
++
++ request.strobe_mask = cpu_to_le32(strobe_mask);
++ return gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_WAKE_PINS_ACQUIRE,
++ &request, sizeof(request),
++ NULL, 0);
++}
++
++int gb_svc_timesync_wake_pins_release(struct gb_svc *svc)
++{
++ struct gb_connection *connection = svc->connection;
++
++ return gb_operation_sync(connection,
++ GB_SVC_TYPE_TIMESYNC_WAKE_PINS_RELEASE,
++ NULL, 0, NULL, 0);
++}
++
++/* Creates bi-directional routes between the devices */
++int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
++ u8 intf2_id, u8 dev2_id)
++{
++ struct gb_svc_route_create_request request;
++
++ request.intf1_id = intf1_id;
++ request.dev1_id = dev1_id;
++ request.intf2_id = intf2_id;
++ request.dev2_id = dev2_id;
++
++ return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
++ &request, sizeof(request), NULL, 0);
++}
++
++/* Destroys bi-directional routes between the devices */
++void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id)
++{
++ struct gb_svc_route_destroy_request request;
++ int ret;
++
++ request.intf1_id = intf1_id;
++ request.intf2_id = intf2_id;
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_DESTROY,
++ &request, sizeof(request), NULL, 0);
++ if (ret) {
++ dev_err(&svc->dev, "failed to destroy route (%u %u): %d\n",
++ intf1_id, intf2_id, ret);
++ }
++}
++
++int gb_svc_intf_set_power_mode(struct gb_svc *svc, u8 intf_id, u8 hs_series,
++ u8 tx_mode, u8 tx_gear, u8 tx_nlanes,
++ u8 tx_amplitude, u8 tx_hs_equalizer,
++ u8 rx_mode, u8 rx_gear, u8 rx_nlanes,
++ u8 flags, u32 quirks,
++ struct gb_svc_l2_timer_cfg *local,
++ struct gb_svc_l2_timer_cfg *remote)
++{
++ struct gb_svc_intf_set_pwrm_request request;
++ struct gb_svc_intf_set_pwrm_response response;
++ int ret;
++ u16 result_code;
++
++ memset(&request, 0, sizeof(request));
++
++ request.intf_id = intf_id;
++ request.hs_series = hs_series;
++ request.tx_mode = tx_mode;
++ request.tx_gear = tx_gear;
++ request.tx_nlanes = tx_nlanes;
++ request.tx_amplitude = tx_amplitude;
++ request.tx_hs_equalizer = tx_hs_equalizer;
++ request.rx_mode = rx_mode;
++ request.rx_gear = rx_gear;
++ request.rx_nlanes = rx_nlanes;
++ request.flags = flags;
++ request.quirks = cpu_to_le32(quirks);
++ if (local)
++ request.local_l2timerdata = *local;
++ if (remote)
++ request.remote_l2timerdata = *remote;
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0)
++ return ret;
++
++ result_code = response.result_code;
++ if (result_code != GB_SVC_SETPWRM_PWR_LOCAL) {
++ dev_err(&svc->dev, "set power mode = %d\n", result_code);
++ return -EIO;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gb_svc_intf_set_power_mode);
++
++int gb_svc_intf_set_power_mode_hibernate(struct gb_svc *svc, u8 intf_id)
++{
++ struct gb_svc_intf_set_pwrm_request request;
++ struct gb_svc_intf_set_pwrm_response response;
++ int ret;
++ u16 result_code;
++
++ memset(&request, 0, sizeof(request));
++
++ request.intf_id = intf_id;
++ request.hs_series = GB_SVC_UNIPRO_HS_SERIES_A;
++ request.tx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
++ request.rx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
++
++ ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
++ &request, sizeof(request),
++ &response, sizeof(response));
++ if (ret < 0) {
++ dev_err(&svc->dev,
++ "failed to send set power mode operation to interface %u: %d\n",
++ intf_id, ret);
++ return ret;
++ }
++
++ result_code = response.result_code;
++ if (result_code != GB_SVC_SETPWRM_PWR_OK) {
++ dev_err(&svc->dev,
++ "failed to hibernate the link for interface %u: %u\n",
++ intf_id, result_code);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++int gb_svc_ping(struct gb_svc *svc)
++{
++ return gb_operation_sync_timeout(svc->connection, GB_SVC_TYPE_PING,
++ NULL, 0, NULL, 0,
++ GB_OPERATION_TIMEOUT_DEFAULT * 2);
++}
++
++static int gb_svc_version_request(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_svc_version_request *request;
++ struct gb_svc_version_response *response;
++
++ if (op->request->payload_size < sizeof(*request)) {
++ dev_err(&svc->dev, "short version request (%zu < %zu)\n",
++ op->request->payload_size,
++ sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ if (request->major > GB_SVC_VERSION_MAJOR) {
++ dev_warn(&svc->dev, "unsupported major version (%u > %u)\n",
++ request->major, GB_SVC_VERSION_MAJOR);
++ return -ENOTSUPP;
++ }
++
++ svc->protocol_major = request->major;
++ svc->protocol_minor = request->minor;
++
++ if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL))
++ return -ENOMEM;
++
++ response = op->response->payload;
++ response->major = svc->protocol_major;
++ response->minor = svc->protocol_minor;
++
++ return 0;
++}
++
++static ssize_t pwr_debugfs_voltage_read(struct file *file, char __user *buf,
++ size_t len, loff_t *offset)
++{
++ struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private;
++ struct gb_svc *svc = pwrmon_rails->svc;
++ int ret, desc;
++ u32 value;
++ char buff[16];
++
++ ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
++ GB_SVC_PWRMON_TYPE_VOL, &value);
++ if (ret) {
++ dev_err(&svc->dev,
++ "failed to get voltage sample %u: %d\n",
++ pwrmon_rails->id, ret);
++ return ret;
++ }
++
++ desc = scnprintf(buff, sizeof(buff), "%u\n", value);
++
++ return simple_read_from_buffer(buf, len, offset, buff, desc);
++}
++
++static ssize_t pwr_debugfs_current_read(struct file *file, char __user *buf,
++ size_t len, loff_t *offset)
++{
++ struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private;
++ struct gb_svc *svc = pwrmon_rails->svc;
++ int ret, desc;
++ u32 value;
++ char buff[16];
++
++ ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
++ GB_SVC_PWRMON_TYPE_CURR, &value);
++ if (ret) {
++ dev_err(&svc->dev,
++ "failed to get current sample %u: %d\n",
++ pwrmon_rails->id, ret);
++ return ret;
++ }
++
++ desc = scnprintf(buff, sizeof(buff), "%u\n", value);
++
++ return simple_read_from_buffer(buf, len, offset, buff, desc);
++}
++
++static ssize_t pwr_debugfs_power_read(struct file *file, char __user *buf,
++ size_t len, loff_t *offset)
++{
++ struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private;
++ struct gb_svc *svc = pwrmon_rails->svc;
++ int ret, desc;
++ u32 value;
++ char buff[16];
++
++ ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
++ GB_SVC_PWRMON_TYPE_PWR, &value);
++ if (ret) {
++ dev_err(&svc->dev, "failed to get power sample %u: %d\n",
++ pwrmon_rails->id, ret);
++ return ret;
++ }
++
++ desc = scnprintf(buff, sizeof(buff), "%u\n", value);
++
++ return simple_read_from_buffer(buf, len, offset, buff, desc);
++}
++
++static const struct file_operations pwrmon_debugfs_voltage_fops = {
++ .read = pwr_debugfs_voltage_read,
++};
++
++static const struct file_operations pwrmon_debugfs_current_fops = {
++ .read = pwr_debugfs_current_read,
++};
++
++static const struct file_operations pwrmon_debugfs_power_fops = {
++ .read = pwr_debugfs_power_read,
++};
++
++static void gb_svc_pwrmon_debugfs_init(struct gb_svc *svc)
++{
++ int i;
++ size_t bufsize;
++ struct dentry *dent;
++ struct gb_svc_pwrmon_rail_names_get_response *rail_names;
++ u8 rail_count;
++
++ dent = debugfs_create_dir("pwrmon", svc->debugfs_dentry);
++ if (IS_ERR_OR_NULL(dent))
++ return;
++
++ if (gb_svc_pwrmon_rail_count_get(svc, &rail_count))
++ goto err_pwrmon_debugfs;
++
++ if (!rail_count || rail_count > GB_SVC_PWRMON_MAX_RAIL_COUNT)
++ goto err_pwrmon_debugfs;
++
++ bufsize = sizeof(*rail_names) +
++ GB_SVC_PWRMON_RAIL_NAME_BUFSIZE * rail_count;
++
++ rail_names = kzalloc(bufsize, GFP_KERNEL);
++ if (!rail_names)
++ goto err_pwrmon_debugfs;
++
++ svc->pwrmon_rails = kcalloc(rail_count, sizeof(*svc->pwrmon_rails),
++ GFP_KERNEL);
++ if (!svc->pwrmon_rails)
++ goto err_pwrmon_debugfs_free;
++
++ if (gb_svc_pwrmon_rail_names_get(svc, rail_names, bufsize))
++ goto err_pwrmon_debugfs_free;
++
++ for (i = 0; i < rail_count; i++) {
++ struct dentry *dir;
++ struct svc_debugfs_pwrmon_rail *rail = &svc->pwrmon_rails[i];
++ char fname[GB_SVC_PWRMON_RAIL_NAME_BUFSIZE];
++
++ snprintf(fname, sizeof(fname), "%s",
++ (char *)&rail_names->name[i]);
++
++ rail->id = i;
++ rail->svc = svc;
++
++ dir = debugfs_create_dir(fname, dent);
++ debugfs_create_file("voltage_now", S_IRUGO, dir, rail,
++ &pwrmon_debugfs_voltage_fops);
++ debugfs_create_file("current_now", S_IRUGO, dir, rail,
++ &pwrmon_debugfs_current_fops);
++ debugfs_create_file("power_now", S_IRUGO, dir, rail,
++ &pwrmon_debugfs_power_fops);
++ }
++
++ kfree(rail_names);
++ return;
++
++err_pwrmon_debugfs_free:
++ kfree(rail_names);
++ kfree(svc->pwrmon_rails);
++ svc->pwrmon_rails = NULL;
++
++err_pwrmon_debugfs:
++ debugfs_remove(dent);
++}
++
++static void gb_svc_debugfs_init(struct gb_svc *svc)
++{
++ svc->debugfs_dentry = debugfs_create_dir(dev_name(&svc->dev),
++ gb_debugfs_get());
++ gb_svc_pwrmon_debugfs_init(svc);
++}
++
++static void gb_svc_debugfs_exit(struct gb_svc *svc)
++{
++ debugfs_remove_recursive(svc->debugfs_dentry);
++ kfree(svc->pwrmon_rails);
++ svc->pwrmon_rails = NULL;
++}
++
++static int gb_svc_hello(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_svc_hello_request *hello_request;
++ int ret;
++
++ if (op->request->payload_size < sizeof(*hello_request)) {
++ dev_warn(&svc->dev, "short hello request (%zu < %zu)\n",
++ op->request->payload_size,
++ sizeof(*hello_request));
++ return -EINVAL;
++ }
++
++ hello_request = op->request->payload;
++ svc->endo_id = le16_to_cpu(hello_request->endo_id);
++ svc->ap_intf_id = hello_request->interface_id;
++
++ ret = device_add(&svc->dev);
++ if (ret) {
++ dev_err(&svc->dev, "failed to register svc device: %d\n", ret);
++ return ret;
++ }
++
++ ret = gb_svc_watchdog_create(svc);
++ if (ret) {
++ dev_err(&svc->dev, "failed to create watchdog: %d\n", ret);
++ goto err_unregister_device;
++ }
++
++ gb_svc_debugfs_init(svc);
++
++ ret = gb_timesync_svc_add(svc);
++ if (ret) {
++ dev_err(&svc->dev, "failed to add SVC to timesync: %d\n", ret);
++ gb_svc_debugfs_exit(svc);
++ goto err_unregister_device;
++ }
++
++ return gb_svc_queue_deferred_request(op);
++
++err_unregister_device:
++ gb_svc_watchdog_destroy(svc);
++ device_del(&svc->dev);
++ return ret;
++}
++
++static struct gb_interface *gb_svc_interface_lookup(struct gb_svc *svc,
++ u8 intf_id)
++{
++ struct gb_host_device *hd = svc->hd;
++ struct gb_module *module;
++ size_t num_interfaces;
++ u8 module_id;
++
++ list_for_each_entry(module, &hd->modules, hd_node) {
++ module_id = module->module_id;
++ num_interfaces = module->num_interfaces;
++
++ if (intf_id >= module_id &&
++ intf_id < module_id + num_interfaces) {
++ return module->interfaces[intf_id - module_id];
++ }
++ }
++
++ return NULL;
++}
++
++static struct gb_module *gb_svc_module_lookup(struct gb_svc *svc, u8 module_id)
++{
++ struct gb_host_device *hd = svc->hd;
++ struct gb_module *module;
++
++ list_for_each_entry(module, &hd->modules, hd_node) {
++ if (module->module_id == module_id)
++ return module;
++ }
++
++ return NULL;
++}
++
++static void gb_svc_process_hello_deferred(struct gb_operation *operation)
++{
++ struct gb_connection *connection = operation->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ int ret;
++
++ /*
++ * XXX This is a hack/work-around to reconfigure the APBridgeA-Switch
++ * link to PWM G2, 1 Lane, Slow Auto, so that it has sufficient
++ * bandwidth for 3 audio streams plus boot-over-UniPro of a hot-plugged
++ * module.
++ *
++ * The code should be removed once SW-2217, Heuristic for UniPro
++ * Power Mode Changes is resolved.
++ */
++ ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id,
++ GB_SVC_UNIPRO_HS_SERIES_A,
++ GB_SVC_UNIPRO_SLOW_AUTO_MODE,
++ 2, 1,
++ GB_SVC_SMALL_AMPLITUDE, GB_SVC_NO_DE_EMPHASIS,
++ GB_SVC_UNIPRO_SLOW_AUTO_MODE,
++ 2, 1,
++ 0, 0,
++ NULL, NULL);
++
++ if (ret)
++ dev_warn(&svc->dev,
++ "power mode change failed on AP to switch link: %d\n",
++ ret);
++}
++
++static void gb_svc_process_module_inserted(struct gb_operation *operation)
++{
++ struct gb_svc_module_inserted_request *request;
++ struct gb_connection *connection = operation->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_host_device *hd = svc->hd;
++ struct gb_module *module;
++ size_t num_interfaces;
++ u8 module_id;
++ u16 flags;
++ int ret;
++
++ /* The request message size has already been verified. */
++ request = operation->request->payload;
++ module_id = request->primary_intf_id;
++ num_interfaces = request->intf_count;
++ flags = le16_to_cpu(request->flags);
++
++ dev_dbg(&svc->dev, "%s - id = %u, num_interfaces = %zu, flags = 0x%04x\n",
++ __func__, module_id, num_interfaces, flags);
++
++ if (flags & GB_SVC_MODULE_INSERTED_FLAG_NO_PRIMARY) {
++ dev_warn(&svc->dev, "no primary interface detected on module %u\n",
++ module_id);
++ }
++
++ module = gb_svc_module_lookup(svc, module_id);
++ if (module) {
++ dev_warn(&svc->dev, "unexpected module-inserted event %u\n",
++ module_id);
++ return;
++ }
++
++ module = gb_module_create(hd, module_id, num_interfaces);
++ if (!module) {
++ dev_err(&svc->dev, "failed to create module\n");
++ return;
++ }
++
++ ret = gb_module_add(module);
++ if (ret) {
++ gb_module_put(module);
++ return;
++ }
++
++ list_add(&module->hd_node, &hd->modules);
++}
++
++static void gb_svc_process_module_removed(struct gb_operation *operation)
++{
++ struct gb_svc_module_removed_request *request;
++ struct gb_connection *connection = operation->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_module *module;
++ u8 module_id;
++
++ /* The request message size has already been verified. */
++ request = operation->request->payload;
++ module_id = request->primary_intf_id;
++
++ dev_dbg(&svc->dev, "%s - id = %u\n", __func__, module_id);
++
++ module = gb_svc_module_lookup(svc, module_id);
++ if (!module) {
++ dev_warn(&svc->dev, "unexpected module-removed event %u\n",
++ module_id);
++ return;
++ }
++
++ module->disconnected = true;
++
++ gb_module_del(module);
++ list_del(&module->hd_node);
++ gb_module_put(module);
++}
++
++static void gb_svc_process_intf_oops(struct gb_operation *operation)
++{
++ struct gb_svc_intf_oops_request *request;
++ struct gb_connection *connection = operation->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_interface *intf;
++ u8 intf_id;
++ u8 reason;
++
++ /* The request message size has already been verified. */
++ request = operation->request->payload;
++ intf_id = request->intf_id;
++ reason = request->reason;
++
++ intf = gb_svc_interface_lookup(svc, intf_id);
++ if (!intf) {
++ dev_warn(&svc->dev, "unexpected interface-oops event %u\n",
++ intf_id);
++ return;
++ }
++
++ dev_info(&svc->dev, "Deactivating interface %u, interface oops reason = %u\n",
++ intf_id, reason);
++
++ mutex_lock(&intf->mutex);
++ intf->disconnected = true;
++ gb_interface_disable(intf);
++ gb_interface_deactivate(intf);
++ mutex_unlock(&intf->mutex);
++}
++
++static void gb_svc_process_intf_mailbox_event(struct gb_operation *operation)
++{
++ struct gb_svc_intf_mailbox_event_request *request;
++ struct gb_connection *connection = operation->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ struct gb_interface *intf;
++ u8 intf_id;
++ u16 result_code;
++ u32 mailbox;
++
++ /* The request message size has already been verified. */
++ request = operation->request->payload;
++ intf_id = request->intf_id;
++ result_code = le16_to_cpu(request->result_code);
++ mailbox = le32_to_cpu(request->mailbox);
++
++ dev_dbg(&svc->dev, "%s - id = %u, result = 0x%04x, mailbox = 0x%08x\n",
++ __func__, intf_id, result_code, mailbox);
++
++ intf = gb_svc_interface_lookup(svc, intf_id);
++ if (!intf) {
++ dev_warn(&svc->dev, "unexpected mailbox event %u\n", intf_id);
++ return;
++ }
++
++ gb_interface_mailbox_event(intf, result_code, mailbox);
++}
++
++static void gb_svc_process_deferred_request(struct work_struct *work)
++{
++ struct gb_svc_deferred_request *dr;
++ struct gb_operation *operation;
++ struct gb_svc *svc;
++ u8 type;
++
++ dr = container_of(work, struct gb_svc_deferred_request, work);
++ operation = dr->operation;
++ svc = gb_connection_get_data(operation->connection);
++ type = operation->request->header->type;
++
++ switch (type) {
++ case GB_SVC_TYPE_SVC_HELLO:
++ gb_svc_process_hello_deferred(operation);
++ break;
++ case GB_SVC_TYPE_MODULE_INSERTED:
++ gb_svc_process_module_inserted(operation);
++ break;
++ case GB_SVC_TYPE_MODULE_REMOVED:
++ gb_svc_process_module_removed(operation);
++ break;
++ case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
++ gb_svc_process_intf_mailbox_event(operation);
++ break;
++ case GB_SVC_TYPE_INTF_OOPS:
++ gb_svc_process_intf_oops(operation);
++ break;
++ default:
++ dev_err(&svc->dev, "bad deferred request type: 0x%02x\n", type);
++ }
++
++ gb_operation_put(operation);
++ kfree(dr);
++}
++
++static int gb_svc_queue_deferred_request(struct gb_operation *operation)
++{
++ struct gb_svc *svc = gb_connection_get_data(operation->connection);
++ struct gb_svc_deferred_request *dr;
++
++ dr = kmalloc(sizeof(*dr), GFP_KERNEL);
++ if (!dr)
++ return -ENOMEM;
++
++ gb_operation_get(operation);
++
++ dr->operation = operation;
++ INIT_WORK(&dr->work, gb_svc_process_deferred_request);
++
++ queue_work(svc->wq, &dr->work);
++
++ return 0;
++}
++
++static int gb_svc_intf_reset_recv(struct gb_operation *op)
++{
++ struct gb_svc *svc = gb_connection_get_data(op->connection);
++ struct gb_message *request = op->request;
++ struct gb_svc_intf_reset_request *reset;
++ u8 intf_id;
++
++ if (request->payload_size < sizeof(*reset)) {
++ dev_warn(&svc->dev, "short reset request received (%zu < %zu)\n",
++ request->payload_size, sizeof(*reset));
++ return -EINVAL;
++ }
++ reset = request->payload;
++
++ intf_id = reset->intf_id;
++
++ /* FIXME Reset the interface here */
++
++ return 0;
++}
++
++static int gb_svc_module_inserted_recv(struct gb_operation *op)
++{
++ struct gb_svc *svc = gb_connection_get_data(op->connection);
++ struct gb_svc_module_inserted_request *request;
++
++ if (op->request->payload_size < sizeof(*request)) {
++ dev_warn(&svc->dev, "short module-inserted request received (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
++ request->primary_intf_id);
++
++ return gb_svc_queue_deferred_request(op);
++}
++
++static int gb_svc_module_removed_recv(struct gb_operation *op)
++{
++ struct gb_svc *svc = gb_connection_get_data(op->connection);
++ struct gb_svc_module_removed_request *request;
++
++ if (op->request->payload_size < sizeof(*request)) {
++ dev_warn(&svc->dev, "short module-removed request received (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
++ request->primary_intf_id);
++
++ return gb_svc_queue_deferred_request(op);
++}
++
++static int gb_svc_intf_oops_recv(struct gb_operation *op)
++{
++ struct gb_svc *svc = gb_connection_get_data(op->connection);
++ struct gb_svc_intf_oops_request *request;
++
++ if (op->request->payload_size < sizeof(*request)) {
++ dev_warn(&svc->dev, "short intf-oops request received (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ return gb_svc_queue_deferred_request(op);
++}
++
++static int gb_svc_intf_mailbox_event_recv(struct gb_operation *op)
++{
++ struct gb_svc *svc = gb_connection_get_data(op->connection);
++ struct gb_svc_intf_mailbox_event_request *request;
++
++ if (op->request->payload_size < sizeof(*request)) {
++ dev_warn(&svc->dev, "short mailbox request received (%zu < %zu)\n",
++ op->request->payload_size, sizeof(*request));
++ return -EINVAL;
++ }
++
++ request = op->request->payload;
++
++ dev_dbg(&svc->dev, "%s - id = %u\n", __func__, request->intf_id);
++
++ return gb_svc_queue_deferred_request(op);
++}
++
++static int gb_svc_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_svc *svc = gb_connection_get_data(connection);
++ u8 type = op->type;
++ int ret = 0;
++
++ /*
++ * SVC requests need to follow a specific order (at least initially) and
++ * below code takes care of enforcing that. The expected order is:
++ * - PROTOCOL_VERSION
++ * - SVC_HELLO
++ * - Any other request, but the earlier two.
++ *
++ * Incoming requests are guaranteed to be serialized and so we don't
++ * need to protect 'state' for any races.
++ */
++ switch (type) {
++ case GB_SVC_TYPE_PROTOCOL_VERSION:
++ if (svc->state != GB_SVC_STATE_RESET)
++ ret = -EINVAL;
++ break;
++ case GB_SVC_TYPE_SVC_HELLO:
++ if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
++ ret = -EINVAL;
++ break;
++ default:
++ if (svc->state != GB_SVC_STATE_SVC_HELLO)
++ ret = -EINVAL;
++ break;
++ }
++
++ if (ret) {
++ dev_warn(&svc->dev, "unexpected request 0x%02x received (state %u)\n",
++ type, svc->state);
++ return ret;
++ }
++
++ switch (type) {
++ case GB_SVC_TYPE_PROTOCOL_VERSION:
++ ret = gb_svc_version_request(op);
++ if (!ret)
++ svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
++ return ret;
++ case GB_SVC_TYPE_SVC_HELLO:
++ ret = gb_svc_hello(op);
++ if (!ret)
++ svc->state = GB_SVC_STATE_SVC_HELLO;
++ return ret;
++ case GB_SVC_TYPE_INTF_RESET:
++ return gb_svc_intf_reset_recv(op);
++ case GB_SVC_TYPE_MODULE_INSERTED:
++ return gb_svc_module_inserted_recv(op);
++ case GB_SVC_TYPE_MODULE_REMOVED:
++ return gb_svc_module_removed_recv(op);
++ case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
++ return gb_svc_intf_mailbox_event_recv(op);
++ case GB_SVC_TYPE_INTF_OOPS:
++ return gb_svc_intf_oops_recv(op);
++ default:
++ dev_warn(&svc->dev, "unsupported request 0x%02x\n", type);
++ return -EINVAL;
++ }
++}
++
++static void gb_svc_release(struct device *dev)
++{
++ struct gb_svc *svc = to_gb_svc(dev);
++
++ if (svc->connection)
++ gb_connection_destroy(svc->connection);
++ ida_destroy(&svc->device_id_map);
++ destroy_workqueue(svc->wq);
++ kfree(svc);
++}
++
++struct device_type greybus_svc_type = {
++ .name = "greybus_svc",
++ .release = gb_svc_release,
++};
++
++struct gb_svc *gb_svc_create(struct gb_host_device *hd)
++{
++ struct gb_svc *svc;
++
++ svc = kzalloc(sizeof(*svc), GFP_KERNEL);
++ if (!svc)
++ return NULL;
++
++ svc->wq = alloc_workqueue("%s:svc", WQ_UNBOUND, 1, dev_name(&hd->dev));
++ if (!svc->wq) {
++ kfree(svc);
++ return NULL;
++ }
++
++ svc->dev.parent = &hd->dev;
++ svc->dev.bus = &greybus_bus_type;
++ svc->dev.type = &greybus_svc_type;
++ svc->dev.groups = svc_groups;
++ svc->dev.dma_mask = svc->dev.parent->dma_mask;
++ device_initialize(&svc->dev);
++
++ dev_set_name(&svc->dev, "%d-svc", hd->bus_id);
++
++ ida_init(&svc->device_id_map);
++ svc->state = GB_SVC_STATE_RESET;
++ svc->hd = hd;
++
++ svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
++ gb_svc_request_handler);
++ if (IS_ERR(svc->connection)) {
++ dev_err(&svc->dev, "failed to create connection: %ld\n",
++ PTR_ERR(svc->connection));
++ goto err_put_device;
++ }
++
++ gb_connection_set_data(svc->connection, svc);
++
++ return svc;
++
++err_put_device:
++ put_device(&svc->dev);
++ return NULL;
++}
++
++int gb_svc_add(struct gb_svc *svc)
++{
++ int ret;
++
++ /*
++ * The SVC protocol is currently driven by the SVC, so the SVC device
++ * is added from the connection request handler when enough
++ * information has been received.
++ */
++ ret = gb_connection_enable(svc->connection);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static void gb_svc_remove_modules(struct gb_svc *svc)
++{
++ struct gb_host_device *hd = svc->hd;
++ struct gb_module *module, *tmp;
++
++ list_for_each_entry_safe(module, tmp, &hd->modules, hd_node) {
++ gb_module_del(module);
++ list_del(&module->hd_node);
++ gb_module_put(module);
++ }
++}
++
++void gb_svc_del(struct gb_svc *svc)
++{
++ gb_connection_disable_rx(svc->connection);
++
++ /*
++ * The SVC device may have been registered from the request handler.
++ */
++ if (device_is_registered(&svc->dev)) {
++ gb_timesync_svc_remove(svc);
++ gb_svc_debugfs_exit(svc);
++ gb_svc_watchdog_destroy(svc);
++ device_del(&svc->dev);
++ }
++
++ flush_workqueue(svc->wq);
++
++ gb_svc_remove_modules(svc);
++
++ gb_connection_disable(svc->connection);
++}
++
++void gb_svc_put(struct gb_svc *svc)
++{
++ put_device(&svc->dev);
++}
+--- /dev/null
++++ b/drivers/greybus/svc.h
+@@ -0,0 +1,109 @@
++/*
++ * Greybus SVC code
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __SVC_H
++#define __SVC_H
++
++#define GB_SVC_CPORT_FLAG_E2EFC BIT(0)
++#define GB_SVC_CPORT_FLAG_CSD_N BIT(1)
++#define GB_SVC_CPORT_FLAG_CSV_N BIT(2)
++
++enum gb_svc_state {
++ GB_SVC_STATE_RESET,
++ GB_SVC_STATE_PROTOCOL_VERSION,
++ GB_SVC_STATE_SVC_HELLO,
++};
++
++enum gb_svc_watchdog_bite {
++ GB_SVC_WATCHDOG_BITE_RESET_UNIPRO = 0,
++ GB_SVC_WATCHDOG_BITE_PANIC_KERNEL,
++};
++
++struct gb_svc_watchdog;
++
++struct svc_debugfs_pwrmon_rail {
++ u8 id;
++ struct gb_svc *svc;
++};
++
++struct gb_svc {
++ struct device dev;
++
++ struct gb_host_device *hd;
++ struct gb_connection *connection;
++ enum gb_svc_state state;
++ struct ida device_id_map;
++ struct workqueue_struct *wq;
++
++ u16 endo_id;
++ u8 ap_intf_id;
++
++ u8 protocol_major;
++ u8 protocol_minor;
++
++ struct gb_svc_watchdog *watchdog;
++ enum gb_svc_watchdog_bite action;
++
++ struct dentry *debugfs_dentry;
++ struct svc_debugfs_pwrmon_rail *pwrmon_rails;
++};
++#define to_gb_svc(d) container_of(d, struct gb_svc, dev)
++
++struct gb_svc *gb_svc_create(struct gb_host_device *hd);
++int gb_svc_add(struct gb_svc *svc);
++void gb_svc_del(struct gb_svc *svc);
++void gb_svc_put(struct gb_svc *svc);
++
++int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
++ u8 measurement_type, u32 *value);
++int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id);
++int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
++ u8 intf2_id, u8 dev2_id);
++void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id);
++int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
++ u8 intf2_id, u16 cport2_id, u8 cport_flags);
++void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
++ u8 intf2_id, u16 cport2_id);
++int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id);
++int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable);
++int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable);
++int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable);
++int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type);
++int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id);
++
++int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
++ u32 *value);
++int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
++ u32 value);
++int gb_svc_intf_set_power_mode(struct gb_svc *svc, u8 intf_id, u8 hs_series,
++ u8 tx_mode, u8 tx_gear, u8 tx_nlanes,
++ u8 tx_amplitude, u8 tx_hs_equalizer,
++ u8 rx_mode, u8 rx_gear, u8 rx_nlanes,
++ u8 flags, u32 quirks,
++ struct gb_svc_l2_timer_cfg *local,
++ struct gb_svc_l2_timer_cfg *remote);
++int gb_svc_intf_set_power_mode_hibernate(struct gb_svc *svc, u8 intf_id);
++int gb_svc_ping(struct gb_svc *svc);
++int gb_svc_watchdog_create(struct gb_svc *svc);
++void gb_svc_watchdog_destroy(struct gb_svc *svc);
++bool gb_svc_watchdog_enabled(struct gb_svc *svc);
++int gb_svc_watchdog_enable(struct gb_svc *svc);
++int gb_svc_watchdog_disable(struct gb_svc *svc);
++int gb_svc_timesync_enable(struct gb_svc *svc, u8 count, u64 frame_time,
++ u32 strobe_delay, u32 refclk);
++int gb_svc_timesync_disable(struct gb_svc *svc);
++int gb_svc_timesync_authoritative(struct gb_svc *svc, u64 *frame_time);
++int gb_svc_timesync_ping(struct gb_svc *svc, u64 *frame_time);
++int gb_svc_timesync_wake_pins_acquire(struct gb_svc *svc, u32 strobe_mask);
++int gb_svc_timesync_wake_pins_release(struct gb_svc *svc);
++
++int gb_svc_protocol_init(void);
++void gb_svc_protocol_exit(void);
++
++#endif /* __SVC_H */
+--- /dev/null
++++ b/drivers/greybus/svc_watchdog.c
+@@ -0,0 +1,198 @@
++/*
++ * SVC Greybus "watchdog" driver.
++ *
++ * Copyright 2016 Google Inc.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/delay.h>
++#include <linux/suspend.h>
++#include <linux/workqueue.h>
++#include "greybus.h"
++
++#define SVC_WATCHDOG_PERIOD (2*HZ)
++
++struct gb_svc_watchdog {
++ struct delayed_work work;
++ struct gb_svc *svc;
++ bool enabled;
++ struct notifier_block pm_notifier;
++};
++
++static struct delayed_work reset_work;
++
++static int svc_watchdog_pm_notifier(struct notifier_block *notifier,
++ unsigned long pm_event, void *unused)
++{
++ struct gb_svc_watchdog *watchdog =
++ container_of(notifier, struct gb_svc_watchdog, pm_notifier);
++
++ switch (pm_event) {
++ case PM_SUSPEND_PREPARE:
++ gb_svc_watchdog_disable(watchdog->svc);
++ break;
++ case PM_POST_SUSPEND:
++ gb_svc_watchdog_enable(watchdog->svc);
++ break;
++ default:
++ break;
++ }
++
++ return NOTIFY_DONE;
++}
++
++static void greybus_reset(struct work_struct *work)
++{
++ static char start_path[256] = "/system/bin/start";
++ static char *envp[] = {
++ "HOME=/",
++ "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
++ NULL,
++ };
++ static char *argv[] = {
++ start_path,
++ "unipro_reset",
++ NULL,
++ };
++
++ printk(KERN_ERR "svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
++ argv[0], argv[1]);
++ call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC);
++}
++
++static void do_work(struct work_struct *work)
++{
++ struct gb_svc_watchdog *watchdog;
++ struct gb_svc *svc;
++ int retval;
++
++ watchdog = container_of(work, struct gb_svc_watchdog, work.work);
++ svc = watchdog->svc;
++
++ dev_dbg(&svc->dev, "%s: ping.\n", __func__);
++ retval = gb_svc_ping(svc);
++ if (retval) {
++ /*
++ * Something went really wrong, let's warn userspace and then
++ * pull the plug and reset the whole greybus network.
++ * We need to do this outside of this workqueue as we will be
++ * tearing down the svc device itself. So queue up
++ * yet-another-callback to do that.
++ */
++ dev_err(&svc->dev,
++ "SVC ping has returned %d, something is wrong!!!\n",
++ retval);
++
++ if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL) {
++ panic("SVC is not responding\n");
++ } else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO) {
++ dev_err(&svc->dev, "Resetting the greybus network, watch out!!!\n");
++
++ INIT_DELAYED_WORK(&reset_work, greybus_reset);
++ schedule_delayed_work(&reset_work, HZ / 2);
++
++ /*
++ * Disable ourselves, we don't want to trip again unless
++ * userspace wants us to.
++ */
++ watchdog->enabled = false;
++ }
++ }
++
++ /* resubmit our work to happen again, if we are still "alive" */
++ if (watchdog->enabled)
++ schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
++}
++
++int gb_svc_watchdog_create(struct gb_svc *svc)
++{
++ struct gb_svc_watchdog *watchdog;
++ int retval;
++
++ if (svc->watchdog)
++ return 0;
++
++ watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL);
++ if (!watchdog)
++ return -ENOMEM;
++
++ watchdog->enabled = false;
++ watchdog->svc = svc;
++ INIT_DELAYED_WORK(&watchdog->work, do_work);
++ svc->watchdog = watchdog;
++
++ watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier;
++ retval = register_pm_notifier(&watchdog->pm_notifier);
++ if (retval) {
++ dev_err(&svc->dev, "error registering pm notifier(%d)\n",
++ retval);
++ goto svc_watchdog_create_err;
++ }
++
++ retval = gb_svc_watchdog_enable(svc);
++ if (retval) {
++ dev_err(&svc->dev, "error enabling watchdog (%d)\n", retval);
++ unregister_pm_notifier(&watchdog->pm_notifier);
++ goto svc_watchdog_create_err;
++ }
++ return retval;
++
++svc_watchdog_create_err:
++ svc->watchdog = NULL;
++ kfree(watchdog);
++
++ return retval;
++}
++
++void gb_svc_watchdog_destroy(struct gb_svc *svc)
++{
++ struct gb_svc_watchdog *watchdog = svc->watchdog;
++
++ if (!watchdog)
++ return;
++
++ unregister_pm_notifier(&watchdog->pm_notifier);
++ gb_svc_watchdog_disable(svc);
++ svc->watchdog = NULL;
++ kfree(watchdog);
++}
++
++bool gb_svc_watchdog_enabled(struct gb_svc *svc)
++{
++ if (!svc || !svc->watchdog)
++ return false;
++ return svc->watchdog->enabled;
++}
++
++int gb_svc_watchdog_enable(struct gb_svc *svc)
++{
++ struct gb_svc_watchdog *watchdog;
++
++ if (!svc->watchdog)
++ return -ENODEV;
++
++ watchdog = svc->watchdog;
++ if (watchdog->enabled)
++ return 0;
++
++ watchdog->enabled = true;
++ schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
++ return 0;
++}
++
++int gb_svc_watchdog_disable(struct gb_svc *svc)
++{
++ struct gb_svc_watchdog *watchdog;
++
++ if (!svc->watchdog)
++ return -ENODEV;
++
++ watchdog = svc->watchdog;
++ if (!watchdog->enabled)
++ return 0;
++
++ watchdog->enabled = false;
++ cancel_delayed_work_sync(&watchdog->work);
++ return 0;
++}
diff --git a/greybus_timesync.patch b/greybus_timesync.patch
new file mode 100644
index 00000000000000..fcdacf64a88cf4
--- /dev/null
+++ b/greybus_timesync.patch
@@ -0,0 +1,1494 @@
+---
+ drivers/greybus/timesync.c | 1357 ++++++++++++++++++++++++++++++++++++
+ drivers/greybus/timesync.h | 45 +
+ drivers/greybus/timesync_platform.c | 77 ++
+ 3 files changed, 1479 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/timesync.c
+@@ -0,0 +1,1357 @@
++/*
++ * TimeSync API driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#include <linux/debugfs.h>
++#include <linux/hrtimer.h>
++#include "greybus.h"
++#include "timesync.h"
++#include "greybus_trace.h"
++
++/*
++ * Minimum inter-strobe value of one millisecond is chosen because it
++ * just-about fits the common definition of a jiffy.
++ *
++ * Maximum value OTOH is constrained by the number of bits the SVC can fit
++ * into a 16 bit up-counter. The SVC configures the timer in microseconds
++ * so the maximum allowable value is 65535 microseconds. We clip that value
++ * to 10000 microseconds for the sake of using nice round base 10 numbers
++ * and since right-now there's no imaginable use-case requiring anything
++ * other than a one millisecond inter-strobe time, let alone something
++ * higher than ten milliseconds.
++ */
++#define GB_TIMESYNC_STROBE_DELAY_US 1000
++#define GB_TIMESYNC_DEFAULT_OFFSET_US 1000
++
++/* Work queue timers long, short and SVC strobe timeout */
++#define GB_TIMESYNC_DELAYED_WORK_LONG msecs_to_jiffies(10)
++#define GB_TIMESYNC_DELAYED_WORK_SHORT msecs_to_jiffies(1)
++#define GB_TIMESYNC_MAX_WAIT_SVC msecs_to_jiffies(5000)
++#define GB_TIMESYNC_KTIME_UPDATE msecs_to_jiffies(1000)
++#define GB_TIMESYNC_MAX_KTIME_CONVERSION 15
++
++/* Maximum number of times we'll retry a failed synchronous sync */
++#define GB_TIMESYNC_MAX_RETRIES 5
++
++/* Reported nanoseconds/femtoseconds per clock */
++static u64 gb_timesync_ns_per_clock;
++static u64 gb_timesync_fs_per_clock;
++
++/* Maximum difference we will accept converting FrameTime to ktime */
++static u32 gb_timesync_max_ktime_diff;
++
++/* Reported clock rate */
++static unsigned long gb_timesync_clock_rate;
++
++/* Workqueue */
++static void gb_timesync_worker(struct work_struct *work);
++
++/* List of SVCs with one FrameTime per SVC */
++static LIST_HEAD(gb_timesync_svc_list);
++
++/* Synchronize parallel contexts accessing a valid timesync_svc pointer */
++static DEFINE_MUTEX(gb_timesync_svc_list_mutex);
++
++/* Structure to convert from FrameTime to timespec/ktime */
++struct gb_timesync_frame_time_data {
++ u64 frame_time;
++ struct timespec ts;
++};
++
++struct gb_timesync_svc {
++ struct list_head list;
++ struct list_head interface_list;
++ struct gb_svc *svc;
++ struct gb_timesync_host_device *timesync_hd;
++
++ spinlock_t spinlock; /* Per SVC spinlock to sync with ISR */
++ struct mutex mutex; /* Per SVC mutex for regular synchronization */
++
++ struct dentry *frame_time_dentry;
++ struct dentry *frame_ktime_dentry;
++ struct workqueue_struct *work_queue;
++ wait_queue_head_t wait_queue;
++ struct delayed_work delayed_work;
++ struct timer_list ktime_timer;
++
++ /* The current local FrameTime */
++ u64 frame_time_offset;
++ struct gb_timesync_frame_time_data strobe_data[GB_TIMESYNC_MAX_STROBES];
++ struct gb_timesync_frame_time_data ktime_data;
++
++ /* The SVC FrameTime and relative AP FrameTime @ last TIMESYNC_PING */
++ u64 svc_ping_frame_time;
++ u64 ap_ping_frame_time;
++
++ /* Transitory settings */
++ u32 strobe_mask;
++ bool offset_down;
++ bool print_ping;
++ bool capture_ping;
++ int strobe;
++
++ /* Current state */
++ int state;
++};
++
++struct gb_timesync_host_device {
++ struct list_head list;
++ struct gb_host_device *hd;
++ u64 ping_frame_time;
++};
++
++struct gb_timesync_interface {
++ struct list_head list;
++ struct gb_interface *interface;
++ u64 ping_frame_time;
++};
++
++enum gb_timesync_state {
++ GB_TIMESYNC_STATE_INVALID = 0,
++ GB_TIMESYNC_STATE_INACTIVE = 1,
++ GB_TIMESYNC_STATE_INIT = 2,
++ GB_TIMESYNC_STATE_WAIT_SVC = 3,
++ GB_TIMESYNC_STATE_AUTHORITATIVE = 4,
++ GB_TIMESYNC_STATE_PING = 5,
++ GB_TIMESYNC_STATE_ACTIVE = 6,
++};
++
++static void gb_timesync_ktime_timer_fn(unsigned long data);
++
++static u64 gb_timesync_adjust_count(struct gb_timesync_svc *timesync_svc,
++ u64 counts)
++{
++ if (timesync_svc->offset_down)
++ return counts - timesync_svc->frame_time_offset;
++ else
++ return counts + timesync_svc->frame_time_offset;
++}
++
++/*
++ * This function provides the authoritative FrameTime to a calling function. It
++ * is designed to be lockless and should remain that way the caller is assumed
++ * to be state-aware.
++ */
++static u64 __gb_timesync_get_frame_time(struct gb_timesync_svc *timesync_svc)
++{
++ u64 clocks = gb_timesync_platform_get_counter();
++
++ return gb_timesync_adjust_count(timesync_svc, clocks);
++}
++
++static void gb_timesync_schedule_svc_timeout(struct gb_timesync_svc
++ *timesync_svc)
++{
++ queue_delayed_work(timesync_svc->work_queue,
++ &timesync_svc->delayed_work,
++ GB_TIMESYNC_MAX_WAIT_SVC);
++}
++
++static void gb_timesync_set_state(struct gb_timesync_svc *timesync_svc,
++ int state)
++{
++ switch (state) {
++ case GB_TIMESYNC_STATE_INVALID:
++ timesync_svc->state = state;
++ wake_up(&timesync_svc->wait_queue);
++ break;
++ case GB_TIMESYNC_STATE_INACTIVE:
++ timesync_svc->state = state;
++ wake_up(&timesync_svc->wait_queue);
++ break;
++ case GB_TIMESYNC_STATE_INIT:
++ if (timesync_svc->state != GB_TIMESYNC_STATE_INVALID) {
++ timesync_svc->strobe = 0;
++ timesync_svc->frame_time_offset = 0;
++ timesync_svc->state = state;
++ cancel_delayed_work(&timesync_svc->delayed_work);
++ queue_delayed_work(timesync_svc->work_queue,
++ &timesync_svc->delayed_work,
++ GB_TIMESYNC_DELAYED_WORK_LONG);
++ }
++ break;
++ case GB_TIMESYNC_STATE_WAIT_SVC:
++ if (timesync_svc->state == GB_TIMESYNC_STATE_INIT)
++ timesync_svc->state = state;
++ break;
++ case GB_TIMESYNC_STATE_AUTHORITATIVE:
++ if (timesync_svc->state == GB_TIMESYNC_STATE_WAIT_SVC) {
++ timesync_svc->state = state;
++ cancel_delayed_work(&timesync_svc->delayed_work);
++ queue_delayed_work(timesync_svc->work_queue,
++ &timesync_svc->delayed_work, 0);
++ }
++ break;
++ case GB_TIMESYNC_STATE_PING:
++ if (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE) {
++ timesync_svc->state = state;
++ queue_delayed_work(timesync_svc->work_queue,
++ &timesync_svc->delayed_work,
++ GB_TIMESYNC_DELAYED_WORK_SHORT);
++ }
++ break;
++ case GB_TIMESYNC_STATE_ACTIVE:
++ if (timesync_svc->state == GB_TIMESYNC_STATE_AUTHORITATIVE ||
++ timesync_svc->state == GB_TIMESYNC_STATE_PING) {
++ timesync_svc->state = state;
++ wake_up(&timesync_svc->wait_queue);
++ }
++ break;
++ }
++
++ if (WARN_ON(timesync_svc->state != state)) {
++ pr_err("Invalid state transition %d=>%d\n",
++ timesync_svc->state, state);
++ }
++}
++
++static void gb_timesync_set_state_atomic(struct gb_timesync_svc *timesync_svc,
++ int state)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++ gb_timesync_set_state(timesync_svc, state);
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++}
++
++static u64 gb_timesync_diff(u64 x, u64 y)
++{
++ if (x > y)
++ return x - y;
++ else
++ return y - x;
++}
++
++static void gb_timesync_adjust_to_svc(struct gb_timesync_svc *svc,
++ u64 svc_frame_time, u64 ap_frame_time)
++{
++ if (svc_frame_time > ap_frame_time) {
++ svc->frame_time_offset = svc_frame_time - ap_frame_time;
++ svc->offset_down = false;
++ } else {
++ svc->frame_time_offset = ap_frame_time - svc_frame_time;
++ svc->offset_down = true;
++ }
++}
++
++/*
++ * Associate a FrameTime with a ktime timestamp represented as struct timespec
++ * Requires the calling context to hold timesync_svc->mutex
++ */
++static void gb_timesync_store_ktime(struct gb_timesync_svc *timesync_svc,
++ struct timespec ts, u64 frame_time)
++{
++ timesync_svc->ktime_data.ts = ts;
++ timesync_svc->ktime_data.frame_time = frame_time;
++}
++
++/*
++ * Find the two pulses that best-match our expected inter-strobe gap and
++ * then calculate the difference between the SVC time at the second pulse
++ * to the local time at the second pulse.
++ */
++static void gb_timesync_collate_frame_time(struct gb_timesync_svc *timesync_svc,
++ u64 *frame_time)
++{
++ int i = 0;
++ u64 delta, ap_frame_time;
++ u64 strobe_delay_ns = GB_TIMESYNC_STROBE_DELAY_US * NSEC_PER_USEC;
++ u64 least = 0;
++
++ for (i = 1; i < GB_TIMESYNC_MAX_STROBES; i++) {
++ delta = timesync_svc->strobe_data[i].frame_time -
++ timesync_svc->strobe_data[i - 1].frame_time;
++ delta *= gb_timesync_ns_per_clock;
++ delta = gb_timesync_diff(delta, strobe_delay_ns);
++
++ if (!least || delta < least) {
++ least = delta;
++ gb_timesync_adjust_to_svc(timesync_svc, frame_time[i],
++ timesync_svc->strobe_data[i].frame_time);
++
++ ap_frame_time = timesync_svc->strobe_data[i].frame_time;
++ ap_frame_time = gb_timesync_adjust_count(timesync_svc,
++ ap_frame_time);
++ gb_timesync_store_ktime(timesync_svc,
++ timesync_svc->strobe_data[i].ts,
++ ap_frame_time);
++
++ pr_debug("adjust %s local %llu svc %llu delta %llu\n",
++ timesync_svc->offset_down ? "down" : "up",
++ timesync_svc->strobe_data[i].frame_time,
++ frame_time[i], delta);
++ }
++ }
++}
++
++static void gb_timesync_teardown(struct gb_timesync_svc *timesync_svc)
++{
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_interface *interface;
++ struct gb_host_device *hd;
++ int ret;
++
++ list_for_each_entry(timesync_interface,
++ &timesync_svc->interface_list, list) {
++ interface = timesync_interface->interface;
++ ret = gb_interface_timesync_disable(interface);
++ if (ret) {
++ dev_err(&interface->dev,
++ "interface timesync_disable %d\n", ret);
++ }
++ }
++
++ hd = timesync_svc->timesync_hd->hd;
++ ret = hd->driver->timesync_disable(hd);
++ if (ret < 0) {
++ dev_err(&hd->dev, "host timesync_disable %d\n",
++ ret);
++ }
++
++ gb_svc_timesync_wake_pins_release(svc);
++ gb_svc_timesync_disable(svc);
++ gb_timesync_platform_unlock_bus();
++
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
++}
++
++static void gb_timesync_platform_lock_bus_fail(struct gb_timesync_svc
++ *timesync_svc, int ret)
++{
++ if (ret == -EAGAIN) {
++ gb_timesync_set_state(timesync_svc, timesync_svc->state);
++ } else {
++ pr_err("Failed to lock timesync bus %d\n", ret);
++ gb_timesync_set_state(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
++ }
++}
++
++static void gb_timesync_enable(struct gb_timesync_svc *timesync_svc)
++{
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_host_device *hd;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_interface *interface;
++ u64 init_frame_time;
++ unsigned long clock_rate = gb_timesync_clock_rate;
++ int ret;
++
++ /*
++ * Get access to the wake pins in the AP and SVC
++ * Release these pins either in gb_timesync_teardown() or in
++ * gb_timesync_authoritative()
++ */
++ ret = gb_timesync_platform_lock_bus(timesync_svc);
++ if (ret < 0) {
++ gb_timesync_platform_lock_bus_fail(timesync_svc, ret);
++ return;
++ }
++ ret = gb_svc_timesync_wake_pins_acquire(svc, timesync_svc->strobe_mask);
++ if (ret) {
++ dev_err(&svc->dev,
++ "gb_svc_timesync_wake_pins_acquire %d\n", ret);
++ gb_timesync_teardown(timesync_svc);
++ return;
++ }
++
++ /* Choose an initial time in the future */
++ init_frame_time = __gb_timesync_get_frame_time(timesync_svc) + 100000UL;
++
++ /* Send enable command to all relevant participants */
++ list_for_each_entry(timesync_interface, &timesync_svc->interface_list,
++ list) {
++ interface = timesync_interface->interface;
++ ret = gb_interface_timesync_enable(interface,
++ GB_TIMESYNC_MAX_STROBES,
++ init_frame_time,
++ GB_TIMESYNC_STROBE_DELAY_US,
++ clock_rate);
++ if (ret) {
++ dev_err(&interface->dev,
++ "interface timesync_enable %d\n", ret);
++ }
++ }
++
++ hd = timesync_svc->timesync_hd->hd;
++ ret = hd->driver->timesync_enable(hd, GB_TIMESYNC_MAX_STROBES,
++ init_frame_time,
++ GB_TIMESYNC_STROBE_DELAY_US,
++ clock_rate);
++ if (ret < 0) {
++ dev_err(&hd->dev, "host timesync_enable %d\n",
++ ret);
++ }
++
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_WAIT_SVC);
++ ret = gb_svc_timesync_enable(svc, GB_TIMESYNC_MAX_STROBES,
++ init_frame_time,
++ GB_TIMESYNC_STROBE_DELAY_US,
++ clock_rate);
++ if (ret) {
++ dev_err(&svc->dev,
++ "gb_svc_timesync_enable %d\n", ret);
++ gb_timesync_teardown(timesync_svc);
++ return;
++ }
++
++ /* Schedule a timeout waiting for SVC to complete strobing */
++ gb_timesync_schedule_svc_timeout(timesync_svc);
++}
++
++static void gb_timesync_authoritative(struct gb_timesync_svc *timesync_svc)
++{
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_host_device *hd;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_interface *interface;
++ u64 svc_frame_time[GB_TIMESYNC_MAX_STROBES];
++ int ret;
++
++ /* Get authoritative time from SVC and adjust local clock */
++ ret = gb_svc_timesync_authoritative(svc, svc_frame_time);
++ if (ret) {
++ dev_err(&svc->dev,
++ "gb_svc_timesync_authoritative %d\n", ret);
++ gb_timesync_teardown(timesync_svc);
++ return;
++ }
++ gb_timesync_collate_frame_time(timesync_svc, svc_frame_time);
++
++ /* Transmit authoritative time to downstream slaves */
++ hd = timesync_svc->timesync_hd->hd;
++ ret = hd->driver->timesync_authoritative(hd, svc_frame_time);
++ if (ret < 0)
++ dev_err(&hd->dev, "host timesync_authoritative %d\n", ret);
++
++ list_for_each_entry(timesync_interface,
++ &timesync_svc->interface_list, list) {
++ interface = timesync_interface->interface;
++ ret = gb_interface_timesync_authoritative(
++ interface,
++ svc_frame_time);
++ if (ret) {
++ dev_err(&interface->dev,
++ "interface timesync_authoritative %d\n", ret);
++ }
++ }
++
++ /* Release wake pins */
++ gb_svc_timesync_wake_pins_release(svc);
++ gb_timesync_platform_unlock_bus();
++
++ /* Transition to state ACTIVE */
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_ACTIVE);
++
++ /* Schedule a ping to verify the synchronized system time */
++ timesync_svc->print_ping = true;
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_PING);
++}
++
++static int __gb_timesync_get_status(struct gb_timesync_svc *timesync_svc)
++{
++ int ret = -EINVAL;
++
++ switch (timesync_svc->state) {
++ case GB_TIMESYNC_STATE_INVALID:
++ case GB_TIMESYNC_STATE_INACTIVE:
++ ret = -ENODEV;
++ break;
++ case GB_TIMESYNC_STATE_INIT:
++ case GB_TIMESYNC_STATE_WAIT_SVC:
++ case GB_TIMESYNC_STATE_AUTHORITATIVE:
++ ret = -EAGAIN;
++ break;
++ case GB_TIMESYNC_STATE_PING:
++ case GB_TIMESYNC_STATE_ACTIVE:
++ ret = 0;
++ break;
++ }
++ return ret;
++}
++
++/*
++ * This routine takes a FrameTime and derives the difference with-respect
++ * to a reference FrameTime/ktime pair. It then returns the calculated
++ * ktime based on the difference between the supplied FrameTime and
++ * the reference FrameTime.
++ *
++ * The time difference is calculated to six decimal places. Taking 19.2MHz
++ * as an example this means we have 52.083333~ nanoseconds per clock or
++ * 52083333~ femtoseconds per clock.
++ *
++ * Naively taking the count difference and converting to
++ * seconds/nanoseconds would quickly see the 0.0833 component produce
++ * noticeable errors. For example a time difference of one second would
++ * loose 19200000 * 0.08333x nanoseconds or 1.59 seconds.
++ *
++ * In contrast calculating in femtoseconds the same example of 19200000 *
++ * 0.000000083333x nanoseconds per count of error is just 1.59 nanoseconds!
++ *
++ * Continuing the example of 19.2 MHz we cap the maximum error difference
++ * at a worst-case 0.3 microseconds over a potential calculation window of
++ * abount 15 seconds, meaning you can convert a FrameTime that is <= 15
++ * seconds older/younger than the reference time with a maximum error of
++ * 0.2385 useconds. Note 19.2MHz is an example frequency not a requirement.
++ */
++static int gb_timesync_to_timespec(struct gb_timesync_svc *timesync_svc,
++ u64 frame_time, struct timespec *ts)
++{
++ unsigned long flags;
++ u64 delta_fs, counts, sec, nsec;
++ bool add;
++ int ret = 0;
++
++ memset(ts, 0x00, sizeof(*ts));
++ mutex_lock(&timesync_svc->mutex);
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++
++ ret = __gb_timesync_get_status(timesync_svc);
++ if (ret)
++ goto done;
++
++ /* Support calculating ktime upwards or downwards from the reference */
++ if (frame_time < timesync_svc->ktime_data.frame_time) {
++ add = false;
++ counts = timesync_svc->ktime_data.frame_time - frame_time;
++ } else {
++ add = true;
++ counts = frame_time - timesync_svc->ktime_data.frame_time;
++ }
++
++ /* Enforce the .23 of a usecond boundary @ 19.2MHz */
++ if (counts > gb_timesync_max_ktime_diff) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ /* Determine the time difference in femtoseconds */
++ delta_fs = counts * gb_timesync_fs_per_clock;
++
++ /* Convert to seconds */
++ sec = delta_fs;
++ do_div(sec, NSEC_PER_SEC);
++ do_div(sec, 1000000UL);
++
++ /* Get the nanosecond remainder */
++ nsec = do_div(delta_fs, sec);
++ do_div(nsec, 1000000UL);
++
++ if (add) {
++ /* Add the calculated offset - overflow nanoseconds upwards */
++ ts->tv_sec = timesync_svc->ktime_data.ts.tv_sec + sec;
++ ts->tv_nsec = timesync_svc->ktime_data.ts.tv_nsec + nsec;
++ if (ts->tv_nsec >= NSEC_PER_SEC) {
++ ts->tv_sec++;
++ ts->tv_nsec -= NSEC_PER_SEC;
++ }
++ } else {
++ /* Subtract the difference over/underflow as necessary */
++ if (nsec > timesync_svc->ktime_data.ts.tv_nsec) {
++ sec++;
++ nsec = nsec + timesync_svc->ktime_data.ts.tv_nsec;
++ nsec = do_div(nsec, NSEC_PER_SEC);
++ } else {
++ nsec = timesync_svc->ktime_data.ts.tv_nsec - nsec;
++ }
++ /* Cannot return a negative second value */
++ if (sec > timesync_svc->ktime_data.ts.tv_sec) {
++ ret = -EINVAL;
++ goto done;
++ }
++ ts->tv_sec = timesync_svc->ktime_data.ts.tv_sec - sec;
++ ts->tv_nsec = nsec;
++ }
++done:
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++ mutex_unlock(&timesync_svc->mutex);
++ return ret;
++}
++
++static size_t gb_timesync_log_frame_time(struct gb_timesync_svc *timesync_svc,
++ char *buf, size_t buflen)
++{
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_host_device *hd;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_interface *interface;
++ unsigned int len;
++ size_t off;
++
++ /* AP/SVC */
++ off = snprintf(buf, buflen, "%s frametime: ap=%llu %s=%llu ",
++ greybus_bus_type.name,
++ timesync_svc->ap_ping_frame_time, dev_name(&svc->dev),
++ timesync_svc->svc_ping_frame_time);
++ len = buflen - off;
++
++ /* APB/GPB */
++ if (len < buflen) {
++ hd = timesync_svc->timesync_hd->hd;
++ off += snprintf(&buf[off], len, "%s=%llu ", dev_name(&hd->dev),
++ timesync_svc->timesync_hd->ping_frame_time);
++ len = buflen - off;
++ }
++
++ list_for_each_entry(timesync_interface,
++ &timesync_svc->interface_list, list) {
++ if (len < buflen) {
++ interface = timesync_interface->interface;
++ off += snprintf(&buf[off], len, "%s=%llu ",
++ dev_name(&interface->dev),
++ timesync_interface->ping_frame_time);
++ len = buflen - off;
++ }
++ }
++ if (len < buflen)
++ off += snprintf(&buf[off], len, "\n");
++ return off;
++}
++
++static size_t gb_timesync_log_frame_ktime(struct gb_timesync_svc *timesync_svc,
++ char *buf, size_t buflen)
++{
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_host_device *hd;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_interface *interface;
++ struct timespec ts;
++ unsigned int len;
++ size_t off;
++
++ /* AP */
++ gb_timesync_to_timespec(timesync_svc, timesync_svc->ap_ping_frame_time,
++ &ts);
++ off = snprintf(buf, buflen, "%s frametime: ap=%lu.%lu ",
++ greybus_bus_type.name, ts.tv_sec, ts.tv_nsec);
++ len = buflen - off;
++ if (len >= buflen)
++ goto done;
++
++ /* SVC */
++ gb_timesync_to_timespec(timesync_svc, timesync_svc->svc_ping_frame_time,
++ &ts);
++ off += snprintf(&buf[off], len, "%s=%lu.%lu ", dev_name(&svc->dev),
++ ts.tv_sec, ts.tv_nsec);
++ len = buflen - off;
++ if (len >= buflen)
++ goto done;
++
++ /* APB/GPB */
++ hd = timesync_svc->timesync_hd->hd;
++ gb_timesync_to_timespec(timesync_svc,
++ timesync_svc->timesync_hd->ping_frame_time,
++ &ts);
++ off += snprintf(&buf[off], len, "%s=%lu.%lu ",
++ dev_name(&hd->dev),
++ ts.tv_sec, ts.tv_nsec);
++ len = buflen - off;
++ if (len >= buflen)
++ goto done;
++
++ list_for_each_entry(timesync_interface,
++ &timesync_svc->interface_list, list) {
++ interface = timesync_interface->interface;
++ gb_timesync_to_timespec(timesync_svc,
++ timesync_interface->ping_frame_time,
++ &ts);
++ off += snprintf(&buf[off], len, "%s=%lu.%lu ",
++ dev_name(&interface->dev),
++ ts.tv_sec, ts.tv_nsec);
++ len = buflen - off;
++ if (len >= buflen)
++ goto done;
++ }
++ off += snprintf(&buf[off], len, "\n");
++done:
++ return off;
++}
++
++/*
++ * Send an SVC initiated wake 'ping' to each TimeSync participant.
++ * Get the FrameTime from each participant associated with the wake
++ * ping.
++ */
++static void gb_timesync_ping(struct gb_timesync_svc *timesync_svc)
++{
++ struct gb_svc *svc = timesync_svc->svc;
++ struct gb_host_device *hd;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_control *control;
++ u64 *ping_frame_time;
++ int ret;
++
++ /* Get access to the wake pins in the AP and SVC */
++ ret = gb_timesync_platform_lock_bus(timesync_svc);
++ if (ret < 0) {
++ gb_timesync_platform_lock_bus_fail(timesync_svc, ret);
++ return;
++ }
++ ret = gb_svc_timesync_wake_pins_acquire(svc, timesync_svc->strobe_mask);
++ if (ret) {
++ dev_err(&svc->dev,
++ "gb_svc_timesync_wake_pins_acquire %d\n", ret);
++ gb_timesync_teardown(timesync_svc);
++ return;
++ }
++
++ /* Have SVC generate a timesync ping */
++ timesync_svc->capture_ping = true;
++ timesync_svc->svc_ping_frame_time = 0;
++ ret = gb_svc_timesync_ping(svc, &timesync_svc->svc_ping_frame_time);
++ timesync_svc->capture_ping = false;
++ if (ret) {
++ dev_err(&svc->dev,
++ "gb_svc_timesync_ping %d\n", ret);
++ gb_timesync_teardown(timesync_svc);
++ return;
++ }
++
++ /* Get the ping FrameTime from each APB/GPB */
++ hd = timesync_svc->timesync_hd->hd;
++ timesync_svc->timesync_hd->ping_frame_time = 0;
++ ret = hd->driver->timesync_get_last_event(hd,
++ &timesync_svc->timesync_hd->ping_frame_time);
++ if (ret)
++ dev_err(&hd->dev, "host timesync_get_last_event %d\n", ret);
++
++ list_for_each_entry(timesync_interface,
++ &timesync_svc->interface_list, list) {
++ control = timesync_interface->interface->control;
++ timesync_interface->ping_frame_time = 0;
++ ping_frame_time = &timesync_interface->ping_frame_time;
++ ret = gb_control_timesync_get_last_event(control,
++ ping_frame_time);
++ if (ret) {
++ dev_err(&timesync_interface->interface->dev,
++ "gb_control_timesync_get_last_event %d\n", ret);
++ }
++ }
++
++ /* Ping success - move to timesync active */
++ gb_svc_timesync_wake_pins_release(svc);
++ gb_timesync_platform_unlock_bus();
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_ACTIVE);
++}
++
++static void gb_timesync_log_ping_time(struct gb_timesync_svc *timesync_svc)
++{
++ char *buf;
++
++ if (!timesync_svc->print_ping)
++ return;
++
++ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (buf) {
++ gb_timesync_log_frame_time(timesync_svc, buf, PAGE_SIZE);
++ dev_dbg(&timesync_svc->svc->dev, "%s", buf);
++ kfree(buf);
++ }
++}
++
++/*
++ * Perform the actual work of scheduled TimeSync logic.
++ */
++static void gb_timesync_worker(struct work_struct *work)
++{
++ struct delayed_work *delayed_work = to_delayed_work(work);
++ struct gb_timesync_svc *timesync_svc =
++ container_of(delayed_work, struct gb_timesync_svc, delayed_work);
++
++ mutex_lock(&timesync_svc->mutex);
++
++ switch (timesync_svc->state) {
++ case GB_TIMESYNC_STATE_INIT:
++ gb_timesync_enable(timesync_svc);
++ break;
++
++ case GB_TIMESYNC_STATE_WAIT_SVC:
++ dev_err(&timesync_svc->svc->dev,
++ "timeout SVC strobe completion %d/%d\n",
++ timesync_svc->strobe, GB_TIMESYNC_MAX_STROBES);
++ gb_timesync_teardown(timesync_svc);
++ break;
++
++ case GB_TIMESYNC_STATE_AUTHORITATIVE:
++ gb_timesync_authoritative(timesync_svc);
++ break;
++
++ case GB_TIMESYNC_STATE_PING:
++ gb_timesync_ping(timesync_svc);
++ gb_timesync_log_ping_time(timesync_svc);
++ break;
++
++ default:
++ pr_err("Invalid state %d for delayed work\n",
++ timesync_svc->state);
++ break;
++ }
++
++ mutex_unlock(&timesync_svc->mutex);
++}
++
++/*
++ * Schedule a new TimeSync INIT or PING operation serialized w/r to
++ * gb_timesync_worker().
++ */
++static int gb_timesync_schedule(struct gb_timesync_svc *timesync_svc, int state)
++{
++ int ret = 0;
++
++ if (state != GB_TIMESYNC_STATE_INIT && state != GB_TIMESYNC_STATE_PING)
++ return -EINVAL;
++
++ mutex_lock(&timesync_svc->mutex);
++ if (timesync_svc->state != GB_TIMESYNC_STATE_INVALID) {
++ gb_timesync_set_state_atomic(timesync_svc, state);
++ } else {
++ ret = -ENODEV;
++ }
++ mutex_unlock(&timesync_svc->mutex);
++ return ret;
++}
++
++static int __gb_timesync_schedule_synchronous(
++ struct gb_timesync_svc *timesync_svc, int state)
++{
++ unsigned long flags;
++ int ret;
++
++ ret = gb_timesync_schedule(timesync_svc, state);
++ if (ret)
++ return ret;
++
++ ret = wait_event_interruptible(timesync_svc->wait_queue,
++ (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE ||
++ timesync_svc->state == GB_TIMESYNC_STATE_INACTIVE ||
++ timesync_svc->state == GB_TIMESYNC_STATE_INVALID));
++ if (ret)
++ return ret;
++
++ mutex_lock(&timesync_svc->mutex);
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++
++ ret = __gb_timesync_get_status(timesync_svc);
++
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++ mutex_unlock(&timesync_svc->mutex);
++
++ return ret;
++}
++
++static struct gb_timesync_svc *gb_timesync_find_timesync_svc(
++ struct gb_host_device *hd)
++{
++ struct gb_timesync_svc *timesync_svc;
++
++ list_for_each_entry(timesync_svc, &gb_timesync_svc_list, list) {
++ if (timesync_svc->svc == hd->svc)
++ return timesync_svc;
++ }
++ return NULL;
++}
++
++static struct gb_timesync_interface *gb_timesync_find_timesync_interface(
++ struct gb_timesync_svc *timesync_svc,
++ struct gb_interface *interface)
++{
++ struct gb_timesync_interface *timesync_interface;
++
++ list_for_each_entry(timesync_interface, &timesync_svc->interface_list, list) {
++ if (timesync_interface->interface == interface)
++ return timesync_interface;
++ }
++ return NULL;
++}
++
++int gb_timesync_schedule_synchronous(struct gb_interface *interface)
++{
++ int ret;
++ struct gb_timesync_svc *timesync_svc;
++ int retries;
++
++ if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
++ return 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ for (retries = 0; retries < GB_TIMESYNC_MAX_RETRIES; retries++) {
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc) {
++ ret = -ENODEV;
++ goto done;
++ }
++
++ ret = __gb_timesync_schedule_synchronous(timesync_svc,
++ GB_TIMESYNC_STATE_INIT);
++ if (!ret)
++ break;
++ }
++ if (ret && retries == GB_TIMESYNC_MAX_RETRIES)
++ ret = -ETIMEDOUT;
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_schedule_synchronous);
++
++void gb_timesync_schedule_asynchronous(struct gb_interface *interface)
++{
++ struct gb_timesync_svc *timesync_svc;
++
++ if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
++ return;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc)
++ goto done;
++
++ gb_timesync_schedule(timesync_svc, GB_TIMESYNC_STATE_INIT);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_schedule_asynchronous);
++
++static ssize_t gb_timesync_ping_read(struct file *file, char __user *ubuf,
++ size_t len, loff_t *offset, bool ktime)
++{
++ struct gb_timesync_svc *timesync_svc = file->f_inode->i_private;
++ char *buf;
++ ssize_t ret = 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ mutex_lock(&timesync_svc->mutex);
++ if (list_empty(&timesync_svc->interface_list))
++ ret = -ENODEV;
++ timesync_svc->print_ping = false;
++ mutex_unlock(&timesync_svc->mutex);
++ if (ret)
++ goto done;
++
++ ret = __gb_timesync_schedule_synchronous(timesync_svc,
++ GB_TIMESYNC_STATE_PING);
++ if (ret)
++ goto done;
++
++ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!buf) {
++ ret = -ENOMEM;
++ goto done;
++ }
++
++ if (ktime)
++ ret = gb_timesync_log_frame_ktime(timesync_svc, buf, PAGE_SIZE);
++ else
++ ret = gb_timesync_log_frame_time(timesync_svc, buf, PAGE_SIZE);
++ if (ret > 0)
++ ret = simple_read_from_buffer(ubuf, len, offset, buf, ret);
++ kfree(buf);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++
++static ssize_t gb_timesync_ping_read_frame_time(struct file *file,
++ char __user *buf,
++ size_t len, loff_t *offset)
++{
++ return gb_timesync_ping_read(file, buf, len, offset, false);
++}
++
++static ssize_t gb_timesync_ping_read_frame_ktime(struct file *file,
++ char __user *buf,
++ size_t len, loff_t *offset)
++{
++ return gb_timesync_ping_read(file, buf, len, offset, true);
++}
++
++static const struct file_operations gb_timesync_debugfs_frame_time_ops = {
++ .read = gb_timesync_ping_read_frame_time,
++};
++
++static const struct file_operations gb_timesync_debugfs_frame_ktime_ops = {
++ .read = gb_timesync_ping_read_frame_ktime,
++};
++
++static int gb_timesync_hd_add(struct gb_timesync_svc *timesync_svc,
++ struct gb_host_device *hd)
++{
++ struct gb_timesync_host_device *timesync_hd;
++
++ timesync_hd = kzalloc(sizeof(*timesync_hd), GFP_KERNEL);
++ if (!timesync_hd)
++ return -ENOMEM;
++
++ WARN_ON(timesync_svc->timesync_hd);
++ timesync_hd->hd = hd;
++ timesync_svc->timesync_hd = timesync_hd;
++
++ return 0;
++}
++
++static void gb_timesync_hd_remove(struct gb_timesync_svc *timesync_svc,
++ struct gb_host_device *hd)
++{
++ if (timesync_svc->timesync_hd->hd == hd) {
++ kfree(timesync_svc->timesync_hd);
++ timesync_svc->timesync_hd = NULL;
++ return;
++ }
++ WARN_ON(1);
++}
++
++int gb_timesync_svc_add(struct gb_svc *svc)
++{
++ struct gb_timesync_svc *timesync_svc;
++ int ret;
++
++ timesync_svc = kzalloc(sizeof(*timesync_svc), GFP_KERNEL);
++ if (!timesync_svc)
++ return -ENOMEM;
++
++ timesync_svc->work_queue =
++ create_singlethread_workqueue("gb-timesync-work_queue");
++
++ if (!timesync_svc->work_queue) {
++ kfree(timesync_svc);
++ return -ENOMEM;
++ }
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ INIT_LIST_HEAD(&timesync_svc->interface_list);
++ INIT_DELAYED_WORK(&timesync_svc->delayed_work, gb_timesync_worker);
++ mutex_init(&timesync_svc->mutex);
++ spin_lock_init(&timesync_svc->spinlock);
++ init_waitqueue_head(&timesync_svc->wait_queue);
++
++ timesync_svc->svc = svc;
++ timesync_svc->frame_time_offset = 0;
++ timesync_svc->capture_ping = false;
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
++
++ timesync_svc->frame_time_dentry =
++ debugfs_create_file("frame-time", S_IRUGO, svc->debugfs_dentry,
++ timesync_svc,
++ &gb_timesync_debugfs_frame_time_ops);
++ timesync_svc->frame_ktime_dentry =
++ debugfs_create_file("frame-ktime", S_IRUGO, svc->debugfs_dentry,
++ timesync_svc,
++ &gb_timesync_debugfs_frame_ktime_ops);
++
++ list_add(&timesync_svc->list, &gb_timesync_svc_list);
++ ret = gb_timesync_hd_add(timesync_svc, svc->hd);
++ if (ret) {
++ list_del(&timesync_svc->list);
++ debugfs_remove(timesync_svc->frame_ktime_dentry);
++ debugfs_remove(timesync_svc->frame_time_dentry);
++ destroy_workqueue(timesync_svc->work_queue);
++ kfree(timesync_svc);
++ goto done;
++ }
++
++ init_timer(&timesync_svc->ktime_timer);
++ timesync_svc->ktime_timer.function = gb_timesync_ktime_timer_fn;
++ timesync_svc->ktime_timer.expires = jiffies + GB_TIMESYNC_KTIME_UPDATE;
++ timesync_svc->ktime_timer.data = (unsigned long)timesync_svc;
++ add_timer(&timesync_svc->ktime_timer);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_svc_add);
++
++void gb_timesync_svc_remove(struct gb_svc *svc)
++{
++ struct gb_timesync_svc *timesync_svc;
++ struct gb_timesync_interface *timesync_interface;
++ struct gb_timesync_interface *next;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
++ if (!timesync_svc)
++ goto done;
++
++ cancel_delayed_work_sync(&timesync_svc->delayed_work);
++
++ mutex_lock(&timesync_svc->mutex);
++
++ gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INVALID);
++ del_timer_sync(&timesync_svc->ktime_timer);
++ gb_timesync_teardown(timesync_svc);
++
++ gb_timesync_hd_remove(timesync_svc, svc->hd);
++ list_for_each_entry_safe(timesync_interface, next,
++ &timesync_svc->interface_list, list) {
++ list_del(&timesync_interface->list);
++ kfree(timesync_interface);
++ }
++ debugfs_remove(timesync_svc->frame_ktime_dentry);
++ debugfs_remove(timesync_svc->frame_time_dentry);
++ destroy_workqueue(timesync_svc->work_queue);
++ list_del(&timesync_svc->list);
++
++ mutex_unlock(&timesync_svc->mutex);
++
++ kfree(timesync_svc);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++}
++EXPORT_SYMBOL_GPL(gb_timesync_svc_remove);
++
++/*
++ * Add a Greybus Interface to the set of TimeSync Interfaces.
++ */
++int gb_timesync_interface_add(struct gb_interface *interface)
++{
++ struct gb_timesync_svc *timesync_svc;
++ struct gb_timesync_interface *timesync_interface;
++ int ret = 0;
++
++ if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
++ return 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc) {
++ ret = -ENODEV;
++ goto done;
++ }
++
++ timesync_interface = kzalloc(sizeof(*timesync_interface), GFP_KERNEL);
++ if (!timesync_interface) {
++ ret = -ENOMEM;
++ goto done;
++ }
++
++ mutex_lock(&timesync_svc->mutex);
++ timesync_interface->interface = interface;
++ list_add(&timesync_interface->list, &timesync_svc->interface_list);
++ timesync_svc->strobe_mask |= 1 << interface->interface_id;
++ mutex_unlock(&timesync_svc->mutex);
++
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_interface_add);
++
++/*
++ * Remove a Greybus Interface from the set of TimeSync Interfaces.
++ */
++void gb_timesync_interface_remove(struct gb_interface *interface)
++{
++ struct gb_timesync_svc *timesync_svc;
++ struct gb_timesync_interface *timesync_interface;
++
++ if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
++ return;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc)
++ goto done;
++
++ timesync_interface = gb_timesync_find_timesync_interface(timesync_svc,
++ interface);
++ if (!timesync_interface)
++ goto done;
++
++ mutex_lock(&timesync_svc->mutex);
++ timesync_svc->strobe_mask &= ~(1 << interface->interface_id);
++ list_del(&timesync_interface->list);
++ kfree(timesync_interface);
++ mutex_unlock(&timesync_svc->mutex);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++}
++EXPORT_SYMBOL_GPL(gb_timesync_interface_remove);
++
++/*
++ * Give the authoritative FrameTime to the calling function. Returns zero if we
++ * are not in GB_TIMESYNC_STATE_ACTIVE.
++ */
++static u64 gb_timesync_get_frame_time(struct gb_timesync_svc *timesync_svc)
++{
++ unsigned long flags;
++ u64 ret;
++
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++ if (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE)
++ ret = __gb_timesync_get_frame_time(timesync_svc);
++ else
++ ret = 0;
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++ return ret;
++}
++
++u64 gb_timesync_get_frame_time_by_interface(struct gb_interface *interface)
++{
++ struct gb_timesync_svc *timesync_svc;
++ u64 ret = 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc)
++ goto done;
++
++ ret = gb_timesync_get_frame_time(timesync_svc);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_get_frame_time_by_interface);
++
++u64 gb_timesync_get_frame_time_by_svc(struct gb_svc *svc)
++{
++ struct gb_timesync_svc *timesync_svc;
++ u64 ret = 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
++ if (!timesync_svc)
++ goto done;
++
++ ret = gb_timesync_get_frame_time(timesync_svc);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_get_frame_time_by_svc);
++
++/* Incrementally updates the conversion base from FrameTime to ktime */
++static void gb_timesync_ktime_timer_fn(unsigned long data)
++{
++ struct gb_timesync_svc *timesync_svc =
++ (struct gb_timesync_svc *)data;
++ unsigned long flags;
++ u64 frame_time;
++ struct timespec ts;
++
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++
++ if (timesync_svc->state != GB_TIMESYNC_STATE_ACTIVE)
++ goto done;
++
++ ktime_get_ts(&ts);
++ frame_time = __gb_timesync_get_frame_time(timesync_svc);
++ gb_timesync_store_ktime(timesync_svc, ts, frame_time);
++
++done:
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++ mod_timer(&timesync_svc->ktime_timer,
++ jiffies + GB_TIMESYNC_KTIME_UPDATE);
++}
++
++int gb_timesync_to_timespec_by_svc(struct gb_svc *svc, u64 frame_time,
++ struct timespec *ts)
++{
++ struct gb_timesync_svc *timesync_svc;
++ int ret = 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
++ if (!timesync_svc) {
++ ret = -ENODEV;
++ goto done;
++ }
++ ret = gb_timesync_to_timespec(timesync_svc, frame_time, ts);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_to_timespec_by_svc);
++
++int gb_timesync_to_timespec_by_interface(struct gb_interface *interface,
++ u64 frame_time, struct timespec *ts)
++{
++ struct gb_timesync_svc *timesync_svc;
++ int ret = 0;
++
++ mutex_lock(&gb_timesync_svc_list_mutex);
++ timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
++ if (!timesync_svc) {
++ ret = -ENODEV;
++ goto done;
++ }
++
++ ret = gb_timesync_to_timespec(timesync_svc, frame_time, ts);
++done:
++ mutex_unlock(&gb_timesync_svc_list_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(gb_timesync_to_timespec_by_interface);
++
++void gb_timesync_irq(struct gb_timesync_svc *timesync_svc)
++{
++ unsigned long flags;
++ u64 strobe_time;
++ bool strobe_is_ping = true;
++ struct timespec ts;
++
++ ktime_get_ts(&ts);
++ strobe_time = __gb_timesync_get_frame_time(timesync_svc);
++
++ spin_lock_irqsave(&timesync_svc->spinlock, flags);
++
++ if (timesync_svc->state == GB_TIMESYNC_STATE_PING) {
++ if (!timesync_svc->capture_ping)
++ goto done_nolog;
++ timesync_svc->ap_ping_frame_time = strobe_time;
++ goto done_log;
++ } else if (timesync_svc->state != GB_TIMESYNC_STATE_WAIT_SVC) {
++ goto done_nolog;
++ }
++
++ timesync_svc->strobe_data[timesync_svc->strobe].frame_time = strobe_time;
++ timesync_svc->strobe_data[timesync_svc->strobe].ts = ts;
++
++ if (++timesync_svc->strobe == GB_TIMESYNC_MAX_STROBES) {
++ gb_timesync_set_state(timesync_svc,
++ GB_TIMESYNC_STATE_AUTHORITATIVE);
++ }
++ strobe_is_ping = false;
++done_log:
++ trace_gb_timesync_irq(strobe_is_ping, timesync_svc->strobe,
++ GB_TIMESYNC_MAX_STROBES, strobe_time);
++done_nolog:
++ spin_unlock_irqrestore(&timesync_svc->spinlock, flags);
++}
++EXPORT_SYMBOL(gb_timesync_irq);
++
++int __init gb_timesync_init(void)
++{
++ int ret = 0;
++
++ ret = gb_timesync_platform_init();
++ if (ret) {
++ pr_err("timesync platform init fail!\n");
++ return ret;
++ }
++
++ gb_timesync_clock_rate = gb_timesync_platform_get_clock_rate();
++
++ /* Calculate nanoseconds and femtoseconds per clock */
++ gb_timesync_fs_per_clock = FSEC_PER_SEC;
++ do_div(gb_timesync_fs_per_clock, gb_timesync_clock_rate);
++ gb_timesync_ns_per_clock = NSEC_PER_SEC;
++ do_div(gb_timesync_ns_per_clock, gb_timesync_clock_rate);
++
++ /* Calculate the maximum number of clocks we will convert to ktime */
++ gb_timesync_max_ktime_diff =
++ GB_TIMESYNC_MAX_KTIME_CONVERSION * gb_timesync_clock_rate;
++
++ pr_info("Time-Sync @ %lu Hz max ktime conversion +/- %d seconds\n",
++ gb_timesync_clock_rate, GB_TIMESYNC_MAX_KTIME_CONVERSION);
++ return 0;
++}
++
++void gb_timesync_exit(void)
++{
++ gb_timesync_platform_exit();
++}
+--- /dev/null
++++ b/drivers/greybus/timesync.h
+@@ -0,0 +1,45 @@
++/*
++ * TimeSync API driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#ifndef __TIMESYNC_H
++#define __TIMESYNC_H
++
++struct gb_svc;
++struct gb_interface;
++struct gb_timesync_svc;
++
++/* Platform */
++u64 gb_timesync_platform_get_counter(void);
++u32 gb_timesync_platform_get_clock_rate(void);
++int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata);
++void gb_timesync_platform_unlock_bus(void);
++
++int gb_timesync_platform_init(void);
++void gb_timesync_platform_exit(void);
++
++/* Core API */
++int gb_timesync_interface_add(struct gb_interface *interface);
++void gb_timesync_interface_remove(struct gb_interface *interface);
++int gb_timesync_svc_add(struct gb_svc *svc);
++void gb_timesync_svc_remove(struct gb_svc *svc);
++
++u64 gb_timesync_get_frame_time_by_interface(struct gb_interface *interface);
++u64 gb_timesync_get_frame_time_by_svc(struct gb_svc *svc);
++int gb_timesync_to_timespec_by_svc(struct gb_svc *svc, u64 frame_time,
++ struct timespec *ts);
++int gb_timesync_to_timespec_by_interface(struct gb_interface *interface,
++ u64 frame_time, struct timespec *ts);
++
++int gb_timesync_schedule_synchronous(struct gb_interface *intf);
++void gb_timesync_schedule_asynchronous(struct gb_interface *intf);
++void gb_timesync_irq(struct gb_timesync_svc *timesync_svc);
++int gb_timesync_init(void);
++void gb_timesync_exit(void);
++
++#endif /* __TIMESYNC_H */
+--- /dev/null
++++ b/drivers/greybus/timesync_platform.c
+@@ -0,0 +1,77 @@
++/*
++ * TimeSync API driver.
++ *
++ * Copyright 2016 Google Inc.
++ * Copyright 2016 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ *
++ * This code reads directly from an ARMv7 memory-mapped timer that lives in
++ * MMIO space. Since this counter lives inside of MMIO space its shared between
++ * cores and that means we don't have to worry about issues like TSC on x86
++ * where each time-stamp-counter (TSC) is local to a particular core.
++ *
++ * Register-level access code is based on
++ * drivers/clocksource/arm_arch_timer.c
++ */
++#include <linux/cpufreq.h>
++#include <linux/of_platform.h>
++
++#include "greybus.h"
++#include "arche_platform.h"
++
++static u32 gb_timesync_clock_frequency;
++int (*arche_platform_change_state_cb)(enum arche_platform_state state,
++ struct gb_timesync_svc *pdata);
++EXPORT_SYMBOL_GPL(arche_platform_change_state_cb);
++
++u64 gb_timesync_platform_get_counter(void)
++{
++ return (u64)get_cycles();
++}
++
++u32 gb_timesync_platform_get_clock_rate(void)
++{
++ if (unlikely(!gb_timesync_clock_frequency))
++ return cpufreq_get(0);
++
++ return gb_timesync_clock_frequency;
++}
++
++int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata)
++{
++ return arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_TIME_SYNC,
++ pdata);
++}
++
++void gb_timesync_platform_unlock_bus(void)
++{
++ arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_ACTIVE, NULL);
++}
++
++static const struct of_device_id arch_timer_of_match[] = {
++ { .compatible = "google,greybus-frame-time-counter", },
++ {},
++};
++
++int __init gb_timesync_platform_init(void)
++{
++ struct device_node *np;
++
++ np = of_find_matching_node(NULL, arch_timer_of_match);
++ if (!np) {
++ /* Tolerate not finding to allow BBB etc to continue */
++ pr_warn("Unable to find a compatible ARMv7 timer\n");
++ return 0;
++ }
++
++ if (of_property_read_u32(np, "clock-frequency",
++ &gb_timesync_clock_frequency)) {
++ pr_err("Unable to find timer clock-frequency\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++void gb_timesync_platform_exit(void) {}
diff --git a/greybus_tools.patch b/greybus_tools.patch
new file mode 100644
index 00000000000000..e24e3689a99373
--- /dev/null
+++ b/greybus_tools.patch
@@ -0,0 +1,1435 @@
+---
+ drivers/greybus/tools/.gitignore | 1
+ drivers/greybus/tools/Android.mk | 10
+ drivers/greybus/tools/Makefile | 31 +
+ drivers/greybus/tools/README.loopback | 198 ++++++
+ drivers/greybus/tools/lbtest | 168 +++++
+ drivers/greybus/tools/loopback_test.c | 1000 ++++++++++++++++++++++++++++++++++
+ 6 files changed, 1408 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/tools/.gitignore
+@@ -0,0 +1 @@
++loopback_test
+--- /dev/null
++++ b/drivers/greybus/tools/Android.mk
+@@ -0,0 +1,10 @@
++LOCAL_PATH:= $(call my-dir)
++
++include $(CLEAR_VARS)
++
++LOCAL_SRC_FILES:= loopback_test.c
++LOCAL_MODULE_TAGS := optional
++LOCAL_MODULE := gb_loopback_test
++
++include $(BUILD_EXECUTABLE)
++
+--- /dev/null
++++ b/drivers/greybus/tools/Makefile
+@@ -0,0 +1,31 @@
++ifeq ($(strip $(V)), 1)
++ Q =
++else
++ Q = @
++endif
++
++CFLAGS += -std=gnu99 -Wall -Wextra -g \
++ -D_GNU_SOURCE \
++ -Wno-unused-parameter \
++ -Wmaybe-uninitialized \
++ -Wredundant-decls \
++ -Wcast-align \
++ -Wsign-compare \
++ -Wno-missing-field-initializers
++
++CC := $(CROSS_COMPILE)gcc
++
++TOOLS = loopback_test
++
++all: $(TOOLS)
++
++%.o: %.c ../greybus_protocols.h
++ @echo ' TARGET_CC $@'
++ $(Q)$(CC) $(CFLAGS) -c $< -o $@
++
++loopback_%: loopback_%.o
++ @echo ' TARGET_LD $@'
++ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
++
++clean::
++ rm -f *.o $(TOOLS)
+--- /dev/null
++++ b/drivers/greybus/tools/README.loopback
+@@ -0,0 +1,198 @@
++
++
++ 1 - LOOPBACK DRIVER
++
++The driver implements the main logic of the loopback test and provides
++sysfs files to configure the test and retrieve the results.
++A user could run a test without the need of the test application given
++that he understands the sysfs interface of the loopback driver.
++
++The loopback kernel driver needs to be loaded and at least one module
++with the loopback feature enabled must be present for the sysfs files to be
++created and for the loopback test application to be able to run.
++
++To load the module:
++# modprobe gb-loopback
++
++
++When the module is probed, New files are available on the sysfs
++directory of the detected loopback device.
++(typically under "/sys/bus/graybus/devices").
++
++Here is a short summary of the sysfs interface files that should be visible:
++
++* Loopback Configuration Files:
++ async - Use asynchronous operations.
++ iteration_max - Number of tests iterations to perform.
++ size - payload size of the transfer.
++ timeout - The number of microseconds to give an individual
++ asynchronous request before timing out.
++ us_wait - Time to wait between 2 messages
++ type - By writing the test type to this file, the test starts.
++ Valid tests are:
++ 0 stop the test
++ 2 - ping
++ 3 - transfer
++ 4 - sink
++
++* Loopback feedback files:
++ error - number of errors that have occurred.
++ iteration_count - Number of iterations performed.
++ requests_completed - Number of requests successfully completed.
++ requests_timedout - Number of requests that have timed out.
++ timeout_max - Max allowed timeout
++ timeout_min - Min allowed timeout.
++
++* Loopback result files:
++ apbridge_unipro_latency_avg
++ apbridge_unipro_latency_max
++ apbridge_unipro_latency_min
++ gpbridge_firmware_latency_avg
++ gpbridge_firmware_latency_max
++ gpbridge_firmware_latency_min
++ requests_per_second_avg
++ requests_per_second_max
++ requests_per_second_min
++ latency_avg
++ latency_max
++ latency_min
++ throughput_avg
++ throughput_max
++ throughput_min
++
++
++
++ 2 - LOOPBACK TEST APPLICATION
++
++The loopback test application manages and formats the results provided by
++the loopback kernel module. The purpose of this application
++is to:
++ - Start and manage multiple loopback device tests concurrently.
++ - Calculate the aggregate results for multiple devices.
++ - Gather and format test results (csv or human readable).
++
++The best way to get up to date usage information for the application is
++usually to pass the "-h" parameter.
++Here is the summary of the available options:
++
++ Mandatory arguments
++ -t must be one of the test names - sink, transfer or ping
++ -i iteration count - the number of iterations to run the test over
++ Optional arguments
++ -S sysfs location - location for greybus 'endo' entires default /sys/bus/greybus/devices/
++ -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/
++ -s size of data packet to send during test - defaults to zero
++ -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc
++ default is zero which means broadcast to all connections
++ -v verbose output
++ -d debug output
++ -r raw data output - when specified the full list of latency values are included in the output CSV
++ -p porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file
++ -a aggregate - show aggregation of all enabled devies
++ -l list found loopback devices and exit.
++ -x Async - Enable async transfers.
++ -o Timeout - Timeout in microseconds for async operations.
++
++
++
++ 3 - REAL WORLD EXAMPLE USAGES
++
++ 3.1 - Using the driver sysfs files to run a test on a single device:
++
++* Run a 1000 transfers of a 100 byte packet. Each transfer is started only
++after the previous one finished successfully:
++ echo 0 > /sys/bus/greybus/devices/1-2.17/type
++ echo 0 > /sys/bus/greybus/devices/1-2.17/async
++ echo 2000 > /sys/bus/greybus/devices/1-2.17/us_wait
++ echo 100 > /sys/bus/greybus/devices/1-2.17/size
++ echo 1000 > /sys/bus/greybus/devices/1-2.17/iteration_max
++ echo 0 > /sys/bus/greybus/devices/1-2.17/mask
++ echo 200000 > /sys/bus/greybus/devices/1-2.17/timeout
++ echo 3 > /sys/bus/greybus/devices/1-2.17/type
++
++* Run a 1000 transfers of a 100 byte packet. Transfers are started without
++waiting for the previous one to finish:
++ echo 0 > /sys/bus/greybus/devices/1-2.17/type
++ echo 3 > /sys/bus/greybus/devices/1-2.17/async
++ echo 0 > /sys/bus/greybus/devices/1-2.17/us_wait
++ echo 100 > /sys/bus/greybus/devices/1-2.17/size
++ echo 1000 > /sys/bus/greybus/devices/1-2.17/iteration_max
++ echo 0 > /sys/bus/greybus/devices/1-2.17/mask
++ echo 200000 > /sys/bus/greybus/devices/1-2.17/timeout
++ echo 3 > /sys/bus/greybus/devices/1-2.17/type
++
++* Read the results from sysfs:
++ cat /sys/bus/greybus/devices/1-2.17/requests_per_second_min
++ cat /sys/bus/greybus/devices/1-2.17/requests_per_second_max
++ cat /sys/bus/greybus/devices/1-2.17/requests_per_second_avg
++
++ cat /sys/bus/greybus/devices/1-2.17/latency_min
++ cat /sys/bus/greybus/devices/1-2.17/latency_max
++ cat /sys/bus/greybus/devices/1-2.17/latency_avg
++
++ cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_min
++ cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_max
++ cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_avg
++
++ cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_min
++ cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_max
++ cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_avg
++
++ cat /sys/bus/greybus/devices/1-2.17/error
++ cat /sys/bus/greybus/devices/1-2.17/requests_completed
++ cat /sys/bus/greybus/devices/1-2.17/requests_timedout
++
++
++3.2 - using the test application:
++
++* Run a transfer test 10 iterations of size 100 bytes on all available devices
++ #/loopback_test -t transfer -i 10 -s 100
++ 1970-1-1 0:10:7,transfer,1-4.17,100,10,0,443,509,471.700012,66,1963,2256,2124.600098,293,102776,118088,109318.898438,15312,1620,1998,1894.099976,378,56,57,56.799999,1
++ 1970-1-1 0:10:7,transfer,1-5.17,100,10,0,399,542,463.399994,143,1845,2505,2175.800049,660,92568,125744,107393.296875,33176,1469,2305,1806.500000,836,56,57,56.799999,1
++
++
++* Show the aggregate results of both devices. ("-a")
++ #/loopback_test -t transfer -i 10 -s 100 -a
++ 1970-1-1 0:10:35,transfer,1-4.17,100,10,0,448,580,494.100006,132,1722,2230,2039.400024,508,103936,134560,114515.703125,30624,1513,1980,1806.900024,467,56,57,57.299999,1
++ 1970-1-1 0:10:35,transfer,1-5.17,100,10,0,383,558,478.600006,175,1791,2606,2115.199951,815,88856,129456,110919.703125,40600,1457,2246,1773.599976,789,56,57,57.099998,1
++ 1970-1-1 0:10:35,transfer,aggregate,100,10,0,383,580,486.000000,197,1722,2606,2077.000000,884,88856,134560,112717.000000,45704,1457,2246,1789.000000,789,56,57,57.000000,1
++
++* Example usage of the mask option to select which devices will
++ run the test (1st, 2nd, or both devices):
++ # /loopback_test -t transfer -i 10 -s 100 -m 1
++ 1970-1-1 0:11:56,transfer,1-4.17,100,10,0,514,558,544.900024,44,1791,1943,1836.599976,152,119248,129456,126301.296875,10208,1600,1001609,101613.601562,1000009,56,57,56.900002,1
++ # /loopback_test -t transfer -i 10 -s 100 -m 2
++ 1970-1-1 0:12:0,transfer,1-5.17,100,10,0,468,554,539.000000,86,1804,2134,1859.500000,330,108576,128528,124932.500000,19952,1606,1626,1619.300049,20,56,57,57.400002,1
++ # /loopback_test -t transfer -i 10 -s 100 -m 3
++ 1970-1-1 0:12:3,transfer,1-4.17,100,10,0,432,510,469.399994,78,1959,2313,2135.800049,354,100224,118320,108785.296875,18096,1610,2024,1893.500000,414,56,57,57.200001,1
++ 1970-1-1 0:12:3,transfer,1-5.17,100,10,0,404,542,468.799988,138,1843,2472,2152.500000,629,93728,125744,108646.101562,32016,1504,2247,1853.099976,743,56,57,57.099998,1
++
++* Show output in human readable format ("-p")
++ # /loopback_test -t transfer -i 10 -s 100 -m 3 -p
++
++ 1970-1-1 0:12:37
++ test: transfer
++ path: 1-4.17
++ size: 100
++ iterations: 10
++ errors: 0
++ async: Disabled
++ requests per-sec: min=390, max=547, average=469.299988, jitter=157
++ ap-throughput B/s: min=90480 max=126904 average=108762.101562 jitter=36424
++ ap-latency usec: min=1826 max=2560 average=2146.000000 jitter=734
++ apbridge-latency usec: min=1620 max=1982 average=1882.099976 jitter=362
++ gpbridge-latency usec: min=56 max=57 average=57.099998 jitter=1
++
++
++ 1970-1-1 0:12:37
++ test: transfer
++ path: 1-5.17
++ size: 100
++ iterations: 10
++ errors: 0
++ async: Disabled
++ requests per-sec: min=397, max=538, average=461.700012, jitter=141
++ ap-throughput B/s: min=92104 max=124816 average=106998.898438 jitter=32712
++ ap-latency usec: min=1856 max=2514 average=2185.699951 jitter=658
++ apbridge-latency usec: min=1460 max=2296 average=1828.599976 jitter=836
++ gpbridge-latency usec: min=56 max=57 average=57.099998 jitter=1
+--- /dev/null
++++ b/drivers/greybus/tools/lbtest
+@@ -0,0 +1,168 @@
++#!/usr/bin/env python
++
++# Copyright (c) 2015 Google, Inc.
++# Copyright (c) 2015 Linaro, Ltd.
++# All rights reserved.
++#
++# Redistribution and use in source and binary forms, with or without
++# modification, are permitted provided that the following conditions are met:
++# 1. Redistributions of source code must retain the above copyright notice,
++# this list of conditions and the following disclaimer.
++# 2. Redistributions in binary form must reproduce the above copyright notice,
++# this list of conditions and the following disclaimer in the documentation
++# and/or other materials provided with the distribution.
++# 3. Neither the name of the copyright holder nor the names of its
++# contributors may be used to endorse or promote products derived from this
++# software without specific prior written permission.
++#
++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
++# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++from __future__ import print_function
++import csv
++import datetime
++import sys
++import time
++
++dict = {'ping': '2', 'transfer': '3', 'sink': '4'}
++verbose = 1
++
++def abort():
++ sys.exit(1)
++
++def usage():
++ print('Usage: looptest TEST SIZE ITERATIONS PATH\n\n'
++ ' Run TEST for a number of ITERATIONS with operation data SIZE bytes\n'
++ ' TEST may be \'ping\' \'transfer\' or \'sink\'\n'
++ ' SIZE indicates the size of transfer <= greybus max payload bytes\n'
++ ' ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n'
++ ' Note if ITERATIONS is set to zero then this utility will\n'
++ ' initiate an infinite (non terminating) test and exit\n'
++ ' without logging any metrics data\n'
++ ' PATH indicates the sysfs path for the loopback greybus entries e.g.\n'
++ ' /sys/bus/greybus/devices/endo0:1:1:1:1/\n'
++ 'Examples:\n'
++ ' looptest transfer 128 10000\n'
++ ' looptest ping 0 128\n'
++ ' looptest sink 2030 32768\n'
++ .format(sys.argv[0]), file=sys.stderr)
++
++ abort()
++
++def read_sysfs_int(path):
++ try:
++ f = open(path, "r");
++ val = f.read();
++ f.close()
++ return int(val)
++ except IOError as e:
++ print("I/O error({0}): {1}".format(e.errno, e.strerror))
++ print("Invalid path %s" % path)
++
++def write_sysfs_val(path, val):
++ try:
++ f = open(path, "r+")
++ f.write(val)
++ f.close()
++ except IOError as e:
++ print("I/O error({0}): {1}".format(e.errno, e.strerror))
++ print("Invalid path %s" % path)
++
++def log_csv(test_name, size, iteration_max, sys_pfx):
++ # file name will test_name_size_iteration_max.csv
++ # every time the same test with the same parameters is run we will then
++ # append to the same CSV with datestamp - representing each test dataset
++ fname = test_name + '_' + size + '_' + str(iteration_max) + '.csv'
++
++ try:
++ # gather data set
++ date = str(datetime.datetime.now())
++ error = read_sysfs_int(sys_pfx + 'error')
++ request_min = read_sysfs_int(sys_pfx + 'requests_per_second_min')
++ request_max = read_sysfs_int(sys_pfx + 'requests_per_second_max')
++ request_avg = read_sysfs_int(sys_pfx + 'requests_per_second_avg')
++ latency_min = read_sysfs_int(sys_pfx + 'latency_min')
++ latency_max = read_sysfs_int(sys_pfx + 'latency_max')
++ latency_avg = read_sysfs_int(sys_pfx + 'latency_avg')
++ throughput_min = read_sysfs_int(sys_pfx + 'throughput_min')
++ throughput_max = read_sysfs_int(sys_pfx + 'throughput_max')
++ throughput_avg = read_sysfs_int(sys_pfx + 'throughput_avg')
++
++ # derive jitter
++ request_jitter = request_max - request_min
++ latency_jitter = latency_max - latency_min
++ throughput_jitter = throughput_max - throughput_min
++
++ # append data set to file
++ with open(fname, 'a') as csvf:
++ row = csv.writer(csvf, delimiter=",", quotechar="'",
++ quoting=csv.QUOTE_MINIMAL)
++ row.writerow([date, test_name, size, iteration_max, error,
++ request_min, request_max, request_avg, request_jitter,
++ latency_min, latency_max, latency_avg, latency_jitter,
++ throughput_min, throughput_max, throughput_avg, throughput_jitter])
++ except IOError as e:
++ print("I/O error({0}): {1}".format(e.errno, e.strerror))
++
++def loopback_run(test_name, size, iteration_max, sys_pfx):
++ test_id = dict[test_name]
++ try:
++ # Terminate any currently running test
++ write_sysfs_val(sys_pfx + 'type', '0')
++ # Set parameter for no wait between messages
++ write_sysfs_val(sys_pfx + 'ms_wait', '0')
++ # Set operation size
++ write_sysfs_val(sys_pfx + 'size', size)
++ # Set iterations
++ write_sysfs_val(sys_pfx + 'iteration_max', str(iteration_max))
++ # Initiate by setting loopback operation type
++ write_sysfs_val(sys_pfx + 'type', test_id)
++ time.sleep(1)
++
++ if iteration_max == 0:
++ print ("Infinite test initiated CSV won't be logged\n")
++ return
++
++ previous = 0
++ err = 0
++ while True:
++ # get current count bail out if it hasn't changed
++ iteration_count = read_sysfs_int(sys_pfx + 'iteration_count')
++ if previous == iteration_count:
++ err = 1
++ break
++ elif iteration_count == iteration_max:
++ break
++ previous = iteration_count
++ if verbose:
++ print('%02d%% complete %d of %d ' %
++ (100 * iteration_count / iteration_max,
++ iteration_count, iteration_max))
++ time.sleep(1)
++ if err:
++ print ('\nError executing test\n')
++ else:
++ log_csv(test_name, size, iteration_max, sys_pfx)
++ except ValueError as ve:
++ print("Error: %s " % format(e.strerror), file=sys.stderr)
++ abort()
++
++def main():
++ if len(sys.argv) < 5:
++ usage()
++
++ if sys.argv[1] in dict.keys():
++ loopback_run(sys.argv[1], sys.argv[2], int(sys.argv[3]), sys.argv[4])
++ else:
++ usage()
++if __name__ == '__main__':
++ main()
+--- /dev/null
++++ b/drivers/greybus/tools/loopback_test.c
+@@ -0,0 +1,1000 @@
++/*
++ * Loopback test application
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Provided under the three clause BSD license found in the LICENSE file.
++ */
++#include <errno.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <poll.h>
++#include <sys/types.h>
++#include <time.h>
++#include <unistd.h>
++#include <dirent.h>
++#include <signal.h>
++
++#define MAX_NUM_DEVICES 10
++#define MAX_SYSFS_PATH 0x200
++#define CSV_MAX_LINE 0x1000
++#define SYSFS_MAX_INT 0x20
++#define MAX_STR_LEN 255
++#define DEFAULT_ASYNC_TIMEOUT 200000
++
++struct dict {
++ char *name;
++ int type;
++};
++
++static struct dict dict[] = {
++ {"ping", 2},
++ {"transfer", 3},
++ {"sink", 4},
++ {NULL,} /* list termination */
++};
++
++struct loopback_results {
++ float latency_avg;
++ uint32_t latency_max;
++ uint32_t latency_min;
++ uint32_t latency_jitter;
++
++ float request_avg;
++ uint32_t request_max;
++ uint32_t request_min;
++ uint32_t request_jitter;
++
++ float throughput_avg;
++ uint32_t throughput_max;
++ uint32_t throughput_min;
++ uint32_t throughput_jitter;
++
++ float apbridge_unipro_latency_avg;
++ uint32_t apbridge_unipro_latency_max;
++ uint32_t apbridge_unipro_latency_min;
++ uint32_t apbridge_unipro_latency_jitter;
++
++ float gbphy_firmware_latency_avg;
++ uint32_t gbphy_firmware_latency_max;
++ uint32_t gbphy_firmware_latency_min;
++ uint32_t gbphy_firmware_latency_jitter;
++
++ uint32_t error;
++};
++
++struct loopback_device {
++ char name[MAX_SYSFS_PATH];
++ char sysfs_entry[MAX_SYSFS_PATH];
++ char debugfs_entry[MAX_SYSFS_PATH];
++ struct loopback_results results;
++};
++
++struct loopback_test {
++ int verbose;
++ int debug;
++ int raw_data_dump;
++ int porcelain;
++ int mask;
++ int size;
++ int iteration_max;
++ int aggregate_output;
++ int test_id;
++ int device_count;
++ int list_devices;
++ int use_async;
++ int async_timeout;
++ int async_outstanding_operations;
++ int us_wait;
++ int file_output;
++ int stop_all;
++ int poll_count;
++ char test_name[MAX_STR_LEN];
++ char sysfs_prefix[MAX_SYSFS_PATH];
++ char debugfs_prefix[MAX_SYSFS_PATH];
++ struct timespec poll_timeout;
++ struct loopback_device devices[MAX_NUM_DEVICES];
++ struct loopback_results aggregate_results;
++ struct pollfd fds[MAX_NUM_DEVICES];
++};
++
++struct loopback_test t;
++
++/* Helper macros to calculate the aggregate results for all devices */
++static inline int device_enabled(struct loopback_test *t, int dev_idx);
++
++#define GET_MAX(field) \
++static int get_##field##_aggregate(struct loopback_test *t) \
++{ \
++ uint32_t max = 0; \
++ int i; \
++ for (i = 0; i < t->device_count; i++) { \
++ if (!device_enabled(t, i)) \
++ continue; \
++ if (t->devices[i].results.field > max) \
++ max = t->devices[i].results.field; \
++ } \
++ return max; \
++} \
++
++#define GET_MIN(field) \
++static int get_##field##_aggregate(struct loopback_test *t) \
++{ \
++ uint32_t min = ~0; \
++ int i; \
++ for (i = 0; i < t->device_count; i++) { \
++ if (!device_enabled(t, i)) \
++ continue; \
++ if (t->devices[i].results.field < min) \
++ min = t->devices[i].results.field; \
++ } \
++ return min; \
++} \
++
++#define GET_AVG(field) \
++static int get_##field##_aggregate(struct loopback_test *t) \
++{ \
++ uint32_t val = 0; \
++ uint32_t count = 0; \
++ int i; \
++ for (i = 0; i < t->device_count; i++) { \
++ if (!device_enabled(t, i)) \
++ continue; \
++ count++; \
++ val += t->devices[i].results.field; \
++ } \
++ if (count) \
++ val /= count; \
++ return val; \
++} \
++
++GET_MAX(throughput_max);
++GET_MAX(request_max);
++GET_MAX(latency_max);
++GET_MAX(apbridge_unipro_latency_max);
++GET_MAX(gbphy_firmware_latency_max);
++GET_MIN(throughput_min);
++GET_MIN(request_min);
++GET_MIN(latency_min);
++GET_MIN(apbridge_unipro_latency_min);
++GET_MIN(gbphy_firmware_latency_min);
++GET_AVG(throughput_avg);
++GET_AVG(request_avg);
++GET_AVG(latency_avg);
++GET_AVG(apbridge_unipro_latency_avg);
++GET_AVG(gbphy_firmware_latency_avg);
++
++void abort()
++{
++ _exit(1);
++}
++
++void usage(void)
++{
++ fprintf(stderr, "Usage: loopback_test TEST [SIZE] ITERATIONS [SYSPATH] [DBGPATH]\n\n"
++ " Run TEST for a number of ITERATIONS with operation data SIZE bytes\n"
++ " TEST may be \'ping\' \'transfer\' or \'sink\'\n"
++ " SIZE indicates the size of transfer <= greybus max payload bytes\n"
++ " ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n"
++ " Note if ITERATIONS is set to zero then this utility will\n"
++ " initiate an infinite (non terminating) test and exit\n"
++ " without logging any metrics data\n"
++ " SYSPATH indicates the sysfs path for the loopback greybus entries e.g.\n"
++ " /sys/bus/greybus/devices\n"
++ " DBGPATH indicates the debugfs path for the loopback greybus entries e.g.\n"
++ " /sys/kernel/debug/gb_loopback/\n"
++ " Mandatory arguments\n"
++ " -t must be one of the test names - sink, transfer or ping\n"
++ " -i iteration count - the number of iterations to run the test over\n"
++ " Optional arguments\n"
++ " -S sysfs location - location for greybus 'endo' entires default /sys/bus/greybus/devices/\n"
++ " -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/\n"
++ " -s size of data packet to send during test - defaults to zero\n"
++ " -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc\n"
++ " default is zero which means broadcast to all connections\n"
++ " -v verbose output\n"
++ " -d debug output\n"
++ " -r raw data output - when specified the full list of latency values are included in the output CSV\n"
++ " -p porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file\n"
++ " -a aggregate - show aggregation of all enabled devices\n"
++ " -l list found loopback devices and exit\n"
++ " -x Async - Enable async transfers\n"
++ " -o Async Timeout - Timeout in uSec for async operations\n"
++ " -O Poll loop time out in seconds(max time a test is expected to last, default: 30sec)\n"
++ " -c Max number of outstanding operations for async operations\n"
++ " -w Wait in uSec between operations\n"
++ " -z Enable output to a CSV file (incompatible with -p)\n"
++ " -f When starting new loopback test, stop currently running tests on all devices\n"
++ "Examples:\n"
++ " Send 10000 transfers with a packet size of 128 bytes to all active connections\n"
++ " loopback_test -t transfer -s 128 -i 10000 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
++ " loopback_test -t transfer -s 128 -i 10000 -m 0\n"
++ " Send 10000 transfers with a packet size of 128 bytes to connection 1 and 4\n"
++ " loopback_test -t transfer -s 128 -i 10000 -m 9\n"
++ " loopback_test -t ping -s 0 128 -i -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
++ " loopback_test -t sink -s 2030 -i 32768 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n");
++ abort();
++}
++
++static inline int device_enabled(struct loopback_test *t, int dev_idx)
++{
++ if (!t->mask || (t->mask & (1 << dev_idx)))
++ return 1;
++
++ return 0;
++}
++
++static void show_loopback_devices(struct loopback_test *t)
++{
++ int i;
++
++ if (t->device_count == 0) {
++ printf("No loopback devices.\n");
++ return;
++ }
++
++ for (i = 0; i < t->device_count; i++)
++ printf("device[%d] = %s\n", i, t->devices[i].name);
++
++}
++
++int open_sysfs(const char *sys_pfx, const char *node, int flags)
++{
++ int fd;
++ char path[MAX_SYSFS_PATH];
++
++ snprintf(path, sizeof(path), "%s%s", sys_pfx, node);
++ fd = open(path, flags);
++ if (fd < 0) {
++ fprintf(stderr, "unable to open %s\n", path);
++ abort();
++ }
++ return fd;
++}
++
++int read_sysfs_int_fd(int fd, const char *sys_pfx, const char *node)
++{
++ char buf[SYSFS_MAX_INT];
++
++ if (read(fd, buf, sizeof(buf)) < 0) {
++ fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
++ strerror(errno));
++ close(fd);
++ abort();
++ }
++ return atoi(buf);
++}
++
++float read_sysfs_float_fd(int fd, const char *sys_pfx, const char *node)
++{
++ char buf[SYSFS_MAX_INT];
++
++ if (read(fd, buf, sizeof(buf)) < 0) {
++
++ fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
++ strerror(errno));
++ close(fd);
++ abort();
++ }
++ return atof(buf);
++}
++
++int read_sysfs_int(const char *sys_pfx, const char *node)
++{
++ int fd, val;
++
++ fd = open_sysfs(sys_pfx, node, O_RDONLY);
++ val = read_sysfs_int_fd(fd, sys_pfx, node);
++ close(fd);
++ return val;
++}
++
++float read_sysfs_float(const char *sys_pfx, const char *node)
++{
++ int fd;
++ float val;
++
++ fd = open_sysfs(sys_pfx, node, O_RDONLY);
++ val = read_sysfs_float_fd(fd, sys_pfx, node);
++ close(fd);
++ return val;
++}
++
++void write_sysfs_val(const char *sys_pfx, const char *node, int val)
++{
++ int fd, len;
++ char buf[SYSFS_MAX_INT];
++
++ fd = open_sysfs(sys_pfx, node, O_RDWR);
++ len = snprintf(buf, sizeof(buf), "%d", val);
++ if (write(fd, buf, len) < 0) {
++ fprintf(stderr, "unable to write to %s%s %s\n", sys_pfx, node,
++ strerror(errno));
++ close(fd);
++ abort();
++ }
++ close(fd);
++}
++
++static int get_results(struct loopback_test *t)
++{
++ struct loopback_device *d;
++ struct loopback_results *r;
++ int i;
++
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ d = &t->devices[i];
++ r = &d->results;
++
++ r->error = read_sysfs_int(d->sysfs_entry, "error");
++ r->request_min = read_sysfs_int(d->sysfs_entry, "requests_per_second_min");
++ r->request_max = read_sysfs_int(d->sysfs_entry, "requests_per_second_max");
++ r->request_avg = read_sysfs_float(d->sysfs_entry, "requests_per_second_avg");
++
++ r->latency_min = read_sysfs_int(d->sysfs_entry, "latency_min");
++ r->latency_max = read_sysfs_int(d->sysfs_entry, "latency_max");
++ r->latency_avg = read_sysfs_float(d->sysfs_entry, "latency_avg");
++
++ r->throughput_min = read_sysfs_int(d->sysfs_entry, "throughput_min");
++ r->throughput_max = read_sysfs_int(d->sysfs_entry, "throughput_max");
++ r->throughput_avg = read_sysfs_float(d->sysfs_entry, "throughput_avg");
++
++ r->apbridge_unipro_latency_min =
++ read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_min");
++ r->apbridge_unipro_latency_max =
++ read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_max");
++ r->apbridge_unipro_latency_avg =
++ read_sysfs_float(d->sysfs_entry, "apbridge_unipro_latency_avg");
++
++ r->gbphy_firmware_latency_min =
++ read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_min");
++ r->gbphy_firmware_latency_max =
++ read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_max");
++ r->gbphy_firmware_latency_avg =
++ read_sysfs_float(d->sysfs_entry, "gbphy_firmware_latency_avg");
++
++ r->request_jitter = r->request_max - r->request_min;
++ r->latency_jitter = r->latency_max - r->latency_min;
++ r->throughput_jitter = r->throughput_max - r->throughput_min;
++ r->apbridge_unipro_latency_jitter =
++ r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
++ r->gbphy_firmware_latency_jitter =
++ r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
++
++ }
++
++ /*calculate the aggregate results of all enabled devices */
++ if (t->aggregate_output) {
++ r = &t->aggregate_results;
++
++ r->request_min = get_request_min_aggregate(t);
++ r->request_max = get_request_max_aggregate(t);
++ r->request_avg = get_request_avg_aggregate(t);
++
++ r->latency_min = get_latency_min_aggregate(t);
++ r->latency_max = get_latency_max_aggregate(t);
++ r->latency_avg = get_latency_avg_aggregate(t);
++
++ r->throughput_min = get_throughput_min_aggregate(t);
++ r->throughput_max = get_throughput_max_aggregate(t);
++ r->throughput_avg = get_throughput_avg_aggregate(t);
++
++ r->apbridge_unipro_latency_min =
++ get_apbridge_unipro_latency_min_aggregate(t);
++ r->apbridge_unipro_latency_max =
++ get_apbridge_unipro_latency_max_aggregate(t);
++ r->apbridge_unipro_latency_avg =
++ get_apbridge_unipro_latency_avg_aggregate(t);
++
++ r->gbphy_firmware_latency_min =
++ get_gbphy_firmware_latency_min_aggregate(t);
++ r->gbphy_firmware_latency_max =
++ get_gbphy_firmware_latency_max_aggregate(t);
++ r->gbphy_firmware_latency_avg =
++ get_gbphy_firmware_latency_avg_aggregate(t);
++
++ r->request_jitter = r->request_max - r->request_min;
++ r->latency_jitter = r->latency_max - r->latency_min;
++ r->throughput_jitter = r->throughput_max - r->throughput_min;
++ r->apbridge_unipro_latency_jitter =
++ r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
++ r->gbphy_firmware_latency_jitter =
++ r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
++
++ }
++
++ return 0;
++}
++
++void log_csv_error(int len, int err)
++{
++ fprintf(stderr, "unable to write %d bytes to csv %s\n", len,
++ strerror(err));
++}
++
++int format_output(struct loopback_test *t,
++ struct loopback_results *r,
++ const char *dev_name,
++ char *buf, int buf_len,
++ struct tm *tm)
++{
++ int len = 0;
++
++ memset(buf, 0x00, buf_len);
++ len = snprintf(buf, buf_len, "%u-%u-%u %u:%u:%u",
++ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_hour, tm->tm_min, tm->tm_sec);
++
++ if (t->porcelain) {
++ len += snprintf(&buf[len], buf_len - len,
++ "\n test:\t\t\t%s\n path:\t\t\t%s\n size:\t\t\t%u\n iterations:\t\t%u\n errors:\t\t%u\n async:\t\t\t%s\n",
++ t->test_name,
++ dev_name,
++ t->size,
++ t->iteration_max,
++ r->error,
++ t->use_async ? "Enabled" : "Disabled");
++
++ len += snprintf(&buf[len], buf_len - len,
++ " requests per-sec:\tmin=%u, max=%u, average=%f, jitter=%u\n",
++ r->request_min,
++ r->request_max,
++ r->request_avg,
++ r->request_jitter);
++
++ len += snprintf(&buf[len], buf_len - len,
++ " ap-throughput B/s:\tmin=%u max=%u average=%f jitter=%u\n",
++ r->throughput_min,
++ r->throughput_max,
++ r->throughput_avg,
++ r->throughput_jitter);
++ len += snprintf(&buf[len], buf_len - len,
++ " ap-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
++ r->latency_min,
++ r->latency_max,
++ r->latency_avg,
++ r->latency_jitter);
++ len += snprintf(&buf[len], buf_len - len,
++ " apbridge-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
++ r->apbridge_unipro_latency_min,
++ r->apbridge_unipro_latency_max,
++ r->apbridge_unipro_latency_avg,
++ r->apbridge_unipro_latency_jitter);
++
++ len += snprintf(&buf[len], buf_len - len,
++ " gbphy-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
++ r->gbphy_firmware_latency_min,
++ r->gbphy_firmware_latency_max,
++ r->gbphy_firmware_latency_avg,
++ r->gbphy_firmware_latency_jitter);
++
++ } else {
++ len += snprintf(&buf[len], buf_len- len, ",%s,%s,%u,%u,%u",
++ t->test_name, dev_name, t->size, t->iteration_max,
++ r->error);
++
++ len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
++ r->request_min,
++ r->request_max,
++ r->request_avg,
++ r->request_jitter);
++
++ len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
++ r->latency_min,
++ r->latency_max,
++ r->latency_avg,
++ r->latency_jitter);
++
++ len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
++ r->throughput_min,
++ r->throughput_max,
++ r->throughput_avg,
++ r->throughput_jitter);
++
++ len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
++ r->apbridge_unipro_latency_min,
++ r->apbridge_unipro_latency_max,
++ r->apbridge_unipro_latency_avg,
++ r->apbridge_unipro_latency_jitter);
++
++ len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
++ r->gbphy_firmware_latency_min,
++ r->gbphy_firmware_latency_max,
++ r->gbphy_firmware_latency_avg,
++ r->gbphy_firmware_latency_jitter);
++ }
++
++ printf("\n%s\n", buf);
++
++ return len;
++}
++
++static int log_results(struct loopback_test *t)
++{
++ int fd, i, len, ret;
++ struct tm tm;
++ time_t local_time;
++ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
++ char file_name[MAX_SYSFS_PATH];
++ char data[CSV_MAX_LINE];
++
++ local_time = time(NULL);
++ tm = *localtime(&local_time);
++
++ /*
++ * file name will test_name_size_iteration_max.csv
++ * every time the same test with the same parameters is run we will then
++ * append to the same CSV with datestamp - representing each test
++ * dataset.
++ */
++ if (t->file_output && !t->porcelain) {
++ snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv",
++ t->test_name, t->size, t->iteration_max);
++
++ fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, mode);
++ if (fd < 0) {
++ fprintf(stderr, "unable to open %s for appendation\n", file_name);
++ abort();
++ }
++
++ }
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ len = format_output(t, &t->devices[i].results,
++ t->devices[i].name,
++ data, sizeof(data), &tm);
++ if (t->file_output && !t->porcelain) {
++ ret = write(fd, data, len);
++ if (ret == -1)
++ fprintf(stderr, "unable to write %d bytes to csv.\n", len);
++ }
++
++ }
++
++
++ if (t->aggregate_output) {
++ len = format_output(t, &t->aggregate_results, "aggregate",
++ data, sizeof(data), &tm);
++ if (t->file_output && !t->porcelain) {
++ ret = write(fd, data, len);
++ if (ret == -1)
++ fprintf(stderr, "unable to write %d bytes to csv.\n", len);
++ }
++ }
++
++ if (t->file_output && !t->porcelain)
++ close(fd);
++
++ return 0;
++}
++
++int is_loopback_device(const char *path, const char *node)
++{
++ char file[MAX_SYSFS_PATH];
++
++ snprintf(file, MAX_SYSFS_PATH, "%s%s/iteration_count", path, node);
++ if (access(file, F_OK) == 0)
++ return 1;
++ return 0;
++}
++
++int find_loopback_devices(struct loopback_test *t)
++{
++ struct dirent **namelist;
++ int i, n, ret;
++ unsigned int dev_id;
++ struct loopback_device *d;
++
++ n = scandir(t->sysfs_prefix, &namelist, NULL, alphasort);
++ if (n < 0) {
++ perror("scandir");
++ ret = -ENODEV;
++ goto baddir;
++ }
++
++ /* Don't include '.' and '..' */
++ if (n <= 2) {
++ ret = -ENOMEM;
++ goto done;
++ }
++
++ for (i = 0; i < n; i++) {
++ ret = sscanf(namelist[i]->d_name, "gb_loopback%u", &dev_id);
++ if (ret != 1)
++ continue;
++
++ if (!is_loopback_device(t->sysfs_prefix, namelist[i]->d_name))
++ continue;
++
++ if (t->device_count == MAX_NUM_DEVICES) {
++ fprintf(stderr, "max number of devices reached!\n");
++ break;
++ }
++
++ d = &t->devices[t->device_count++];
++ snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id);
++
++ snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/",
++ t->sysfs_prefix, d->name);
++
++ snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s",
++ t->debugfs_prefix, d->name);
++
++ if (t->debug)
++ printf("add %s %s\n", d->sysfs_entry,
++ d->debugfs_entry);
++ }
++
++ ret = 0;
++done:
++ for (i = 0; i < n; i++)
++ free(namelist[n]);
++ free(namelist);
++baddir:
++ return ret;
++}
++
++static int open_poll_files(struct loopback_test *t)
++{
++ struct loopback_device *dev;
++ char buf[MAX_STR_LEN];
++ char dummy;
++ int fds_idx = 0;
++ int i;
++
++ for (i = 0; i < t->device_count; i++) {
++ dev = &t->devices[i];
++
++ if (!device_enabled(t, i))
++ continue;
++
++ snprintf(buf, sizeof(buf), "%s%s", dev->sysfs_entry, "iteration_count");
++ t->fds[fds_idx].fd = open(buf, O_RDONLY);
++ if (t->fds[fds_idx].fd < 0) {
++ fprintf(stderr, "Error opening poll file!\n");
++ goto err;
++ }
++ read(t->fds[fds_idx].fd, &dummy, 1);
++ t->fds[fds_idx].events = POLLERR|POLLPRI;
++ t->fds[fds_idx].revents = 0;
++ fds_idx++;
++ }
++
++ t->poll_count = fds_idx;
++
++ return 0;
++
++err:
++ for (i = 0; i < fds_idx; i++)
++ close(t->fds[fds_idx].fd);
++
++ return -1;
++}
++
++static int close_poll_files(struct loopback_test *t)
++{
++ int i;
++ for (i = 0; i < t->poll_count; i++)
++ close(t->fds[i].fd);
++
++ return 0;
++}
++static int is_complete(struct loopback_test *t)
++{
++ int iteration_count;
++ int i;
++
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ iteration_count = read_sysfs_int(t->devices[i].sysfs_entry,
++ "iteration_count");
++
++ /* at least one device did not finish yet */
++ if (iteration_count != t->iteration_max)
++ return 0;
++ }
++
++ return 1;
++}
++
++static void stop_tests(struct loopback_test *t)
++{
++ int i;
++
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++ write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
++ }
++}
++
++static void handler(int sig) { /* do nothing */ }
++
++static int wait_for_complete(struct loopback_test *t)
++{
++ int number_of_events = 0;
++ char dummy;
++ int ret;
++ int i;
++ struct timespec *ts = NULL;
++ struct sigaction sa;
++ sigset_t mask_old, mask;
++
++ sigemptyset(&mask);
++ sigemptyset(&mask_old);
++ sigaddset(&mask, SIGINT);
++ sigprocmask(SIG_BLOCK, &mask, &mask_old);
++
++ sa.sa_handler = handler;
++ sa.sa_flags = 0;
++ sigemptyset(&sa.sa_mask);
++ if (sigaction(SIGINT, &sa, NULL) == -1) {
++ fprintf(stderr, "sigaction error\n");
++ return -1;
++ }
++
++ if (t->poll_timeout.tv_sec != 0)
++ ts = &t->poll_timeout;
++
++ while (1) {
++
++ ret = ppoll(t->fds, t->poll_count, ts, &mask_old);
++ if (ret <= 0) {
++ stop_tests(t);
++ fprintf(stderr, "Poll exit with errno %d\n", errno);
++ return -1;
++ }
++
++ for (i = 0; i < t->poll_count; i++) {
++ if (t->fds[i].revents & POLLPRI) {
++ /* Dummy read to clear the event */
++ read(t->fds[i].fd, &dummy, 1);
++ number_of_events++;
++ }
++ }
++
++ if (number_of_events == t->poll_count)
++ break;
++ }
++
++ if (!is_complete(t)) {
++ fprintf(stderr, "Iteration count did not finish!\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static void prepare_devices(struct loopback_test *t)
++{
++ int i;
++
++ /* Cancel any running tests on enabled devices. If
++ * stop_all option is given, stop test on all devices.
++ */
++ for (i = 0; i < t->device_count; i++)
++ if (t->stop_all || device_enabled(t, i))
++ write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
++
++
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ write_sysfs_val(t->devices[i].sysfs_entry, "us_wait",
++ t->us_wait);
++
++ /* Set operation size */
++ write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
++
++ /* Set iterations */
++ write_sysfs_val(t->devices[i].sysfs_entry, "iteration_max",
++ t->iteration_max);
++
++ if (t->use_async) {
++ write_sysfs_val(t->devices[i].sysfs_entry,
++ "async", 1);
++ write_sysfs_val(t->devices[i].sysfs_entry,
++ "timeout", t->async_timeout);
++ write_sysfs_val(t->devices[i].sysfs_entry,
++ "outstanding_operations_max",
++ t->async_outstanding_operations);
++ } else
++ write_sysfs_val(t->devices[i].sysfs_entry,
++ "async", 0);
++ }
++}
++
++static int start(struct loopback_test *t)
++{
++ int i;
++
++ /* the test starts by writing test_id to the type file. */
++ for (i = 0; i < t->device_count; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ write_sysfs_val(t->devices[i].sysfs_entry, "type", t->test_id);
++ }
++
++ return 0;
++}
++
++
++void loopback_run(struct loopback_test *t)
++{
++ int i;
++ int ret;
++
++ for (i = 0; dict[i].name != NULL; i++) {
++ if (strstr(dict[i].name, t->test_name))
++ t->test_id = dict[i].type;
++ }
++ if (!t->test_id) {
++ fprintf(stderr, "invalid test %s\n", t->test_name);
++ usage();
++ return;
++ }
++
++ prepare_devices(t);
++
++ ret = open_poll_files(t);
++ if (ret)
++ goto err;
++
++ start(t);
++
++ ret = wait_for_complete(t);
++ close_poll_files(t);
++ if (ret)
++ goto err;
++
++
++ get_results(t);
++
++ log_results(t);
++
++ return;
++
++err:
++ printf("Error running test\n");
++ return;
++}
++
++static int sanity_check(struct loopback_test *t)
++{
++ int i;
++
++ if (t->device_count == 0) {
++ fprintf(stderr, "No loopback devices found\n");
++ return -1;
++ }
++
++ for (i = 0; i < MAX_NUM_DEVICES; i++) {
++ if (!device_enabled(t, i))
++ continue;
++
++ if (t->mask && !strcmp(t->devices[i].name, "")) {
++ fprintf(stderr, "Bad device mask %x\n", (1 << i));
++ return -1;
++ }
++
++ }
++
++
++ return 0;
++}
++
++int main(int argc, char *argv[])
++{
++ int o, ret;
++ char *sysfs_prefix = "/sys/class/gb_loopback/";
++ char *debugfs_prefix = "/sys/kernel/debug/gb_loopback/";
++
++ memset(&t, 0, sizeof(t));
++
++ while ((o = getopt(argc, argv,
++ "t:s:i:S:D:m:v::d::r::p::a::l::x::o:O:c:w:z::f::")) != -1) {
++ switch (o) {
++ case 't':
++ snprintf(t.test_name, MAX_STR_LEN, "%s", optarg);
++ break;
++ case 's':
++ t.size = atoi(optarg);
++ break;
++ case 'i':
++ t.iteration_max = atoi(optarg);
++ break;
++ case 'S':
++ snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
++ break;
++ case 'D':
++ snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
++ break;
++ case 'm':
++ t.mask = atol(optarg);
++ break;
++ case 'v':
++ t.verbose = 1;
++ break;
++ case 'd':
++ t.debug = 1;
++ break;
++ case 'r':
++ t.raw_data_dump = 1;
++ break;
++ case 'p':
++ t.porcelain = 1;
++ break;
++ case 'a':
++ t.aggregate_output = 1;
++ break;
++ case 'l':
++ t.list_devices = 1;
++ break;
++ case 'x':
++ t.use_async = 1;
++ break;
++ case 'o':
++ t.async_timeout = atoi(optarg);
++ break;
++ case 'O':
++ t.poll_timeout.tv_sec = atoi(optarg);
++ break;
++ case 'c':
++ t.async_outstanding_operations = atoi(optarg);
++ break;
++ case 'w':
++ t.us_wait = atoi(optarg);
++ break;
++ case 'z':
++ t.file_output = 1;
++ break;
++ case 'f':
++ t.stop_all = 1;
++ break;
++ default:
++ usage();
++ return -EINVAL;
++ }
++ }
++
++ if (!strcmp(t.sysfs_prefix, ""))
++ snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", sysfs_prefix);
++
++ if (!strcmp(t.debugfs_prefix, ""))
++ snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", debugfs_prefix);
++
++ ret = find_loopback_devices(&t);
++ if (ret)
++ return ret;
++ ret = sanity_check(&t);
++ if (ret)
++ return ret;
++
++ if (t.list_devices) {
++ show_loopback_devices(&t);
++ return 0;
++ }
++
++ if (t.test_name[0] == '\0' || t.iteration_max == 0)
++ usage();
++
++ if (t.async_timeout == 0)
++ t.async_timeout = DEFAULT_ASYNC_TIMEOUT;
++
++ loopback_run(&t);
++
++ return 0;
++}
diff --git a/greybus_trace.patch b/greybus_trace.patch
new file mode 100644
index 00000000000000..c14c444932b89f
--- /dev/null
+++ b/greybus_trace.patch
@@ -0,0 +1,538 @@
+---
+ drivers/greybus/greybus_trace.h | 531 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 531 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/greybus_trace.h
+@@ -0,0 +1,531 @@
++/*
++ * Greybus driver and device API
++ *
++ * Copyright 2015 Google Inc.
++ * Copyright 2015 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM greybus
++
++#if !defined(_TRACE_GREYBUS_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_GREYBUS_H
++
++#include <linux/tracepoint.h>
++
++struct gb_message;
++struct gb_operation;
++struct gb_connection;
++struct gb_bundle;
++struct gb_host_device;
++
++DECLARE_EVENT_CLASS(gb_message,
++
++ TP_PROTO(struct gb_message *message),
++
++ TP_ARGS(message),
++
++ TP_STRUCT__entry(
++ __field(u16, size)
++ __field(u16, operation_id)
++ __field(u8, type)
++ __field(u8, result)
++ ),
++
++ TP_fast_assign(
++ __entry->size = le16_to_cpu(message->header->size);
++ __entry->operation_id =
++ le16_to_cpu(message->header->operation_id);
++ __entry->type = message->header->type;
++ __entry->result = message->header->result;
++ ),
++
++ TP_printk("size=%hu operation_id=0x%04x type=0x%02x result=0x%02x",
++ __entry->size, __entry->operation_id,
++ __entry->type, __entry->result)
++);
++
++#define DEFINE_MESSAGE_EVENT(name) \
++ DEFINE_EVENT(gb_message, name, \
++ TP_PROTO(struct gb_message *message), \
++ TP_ARGS(message))
++
++/*
++ * Occurs immediately before calling a host device's message_send()
++ * method.
++ */
++DEFINE_MESSAGE_EVENT(gb_message_send);
++
++/*
++ * Occurs after an incoming request message has been received
++ */
++DEFINE_MESSAGE_EVENT(gb_message_recv_request);
++
++/*
++ * Occurs after an incoming response message has been received,
++ * after its matching request has been found.
++ */
++DEFINE_MESSAGE_EVENT(gb_message_recv_response);
++
++/*
++ * Occurs after an operation has been canceled, possibly before the
++ * cancellation is complete.
++ */
++DEFINE_MESSAGE_EVENT(gb_message_cancel_outgoing);
++
++/*
++ * Occurs when an incoming request is cancelled; if the response has
++ * been queued for sending, this occurs after it is sent.
++ */
++DEFINE_MESSAGE_EVENT(gb_message_cancel_incoming);
++
++/*
++ * Occurs in the host driver message_send() function just prior to
++ * handing off the data to be processed by hardware.
++ */
++DEFINE_MESSAGE_EVENT(gb_message_submit);
++
++#undef DEFINE_MESSAGE_EVENT
++
++DECLARE_EVENT_CLASS(gb_operation,
++
++ TP_PROTO(struct gb_operation *operation),
++
++ TP_ARGS(operation),
++
++ TP_STRUCT__entry(
++ __field(u16, cport_id) /* CPort of HD side of connection */
++ __field(u16, id) /* Operation ID */
++ __field(u8, type)
++ __field(unsigned long, flags)
++ __field(int, active)
++ __field(int, waiters)
++ __field(int, errno)
++ ),
++
++ TP_fast_assign(
++ __entry->cport_id = operation->connection->hd_cport_id;
++ __entry->id = operation->id;
++ __entry->type = operation->type;
++ __entry->flags = operation->flags;
++ __entry->active = operation->active;
++ __entry->waiters = atomic_read(&operation->waiters);
++ __entry->errno = operation->errno;
++ ),
++
++ TP_printk("id=%04x type=0x%02x cport_id=%04x flags=0x%lx active=%d waiters=%d errno=%d",
++ __entry->id, __entry->cport_id, __entry->type, __entry->flags,
++ __entry->active, __entry->waiters, __entry->errno)
++);
++
++#define DEFINE_OPERATION_EVENT(name) \
++ DEFINE_EVENT(gb_operation, name, \
++ TP_PROTO(struct gb_operation *operation), \
++ TP_ARGS(operation))
++
++/*
++ * Occurs after a new operation is created for an outgoing request
++ * has been successfully created.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_create);
++
++/*
++ * Occurs after a new core operation has been created.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_create_core);
++
++/*
++ * Occurs after a new operation has been created for an incoming
++ * request has been successfully created and initialized.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_create_incoming);
++
++/*
++ * Occurs when the last reference to an operation has been dropped,
++ * prior to freeing resources.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_destroy);
++
++/*
++ * Occurs when an operation has been marked active, after updating
++ * its active count.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_get_active);
++
++/*
++ * Occurs when an operation has been marked active, before updating
++ * its active count.
++ */
++DEFINE_OPERATION_EVENT(gb_operation_put_active);
++
++#undef DEFINE_OPERATION_EVENT
++
++DECLARE_EVENT_CLASS(gb_connection,
++
++ TP_PROTO(struct gb_connection *connection),
++
++ TP_ARGS(connection),
++
++ TP_STRUCT__entry(
++ __field(int, hd_bus_id)
++ __field(u8, bundle_id)
++ /* name contains "hd_cport_id/intf_id:cport_id" */
++ __dynamic_array(char, name, sizeof(connection->name))
++ __field(enum gb_connection_state, state)
++ __field(unsigned long, flags)
++ ),
++
++ TP_fast_assign(
++ __entry->hd_bus_id = connection->hd->bus_id;
++ __entry->bundle_id = connection->bundle ?
++ connection->bundle->id : BUNDLE_ID_NONE;
++ memcpy(__get_str(name), connection->name,
++ sizeof(connection->name));
++ __entry->state = connection->state;
++ __entry->flags = connection->flags;
++ ),
++
++ TP_printk("hd_bus_id=%d bundle_id=0x%02x name=\"%s\" state=%u flags=0x%lx",
++ __entry->hd_bus_id, __entry->bundle_id, __get_str(name),
++ (unsigned int)__entry->state, __entry->flags)
++);
++
++#define DEFINE_CONNECTION_EVENT(name) \
++ DEFINE_EVENT(gb_connection, name, \
++ TP_PROTO(struct gb_connection *connection), \
++ TP_ARGS(connection))
++
++/*
++ * Occurs after a new connection is successfully created.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_create);
++
++/*
++ * Occurs when the last reference to a connection has been dropped,
++ * before its resources are freed.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_release);
++
++/*
++ * Occurs when a new reference to connection is added, currently
++ * only when a message over the connection is received.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_get);
++
++/*
++ * Occurs when a new reference to connection is dropped, after a
++ * a received message is handled, or when the connection is
++ * destroyed.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_put);
++
++/*
++ * Occurs when a request to enable a connection is made, either for
++ * transmit only, or for both transmit and receive.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_enable);
++
++/*
++ * Occurs when a request to disable a connection is made, either for
++ * receive only, or for both transmit and receive. Also occurs when
++ * a request to forcefully disable a connection is made.
++ */
++DEFINE_CONNECTION_EVENT(gb_connection_disable);
++
++#undef DEFINE_CONNECTION_EVENT
++
++DECLARE_EVENT_CLASS(gb_bundle,
++
++ TP_PROTO(struct gb_bundle *bundle),
++
++ TP_ARGS(bundle),
++
++ TP_STRUCT__entry(
++ __field(u8, intf_id)
++ __field(u8, id)
++ __field(u8, class)
++ __field(size_t, num_cports)
++ ),
++
++ TP_fast_assign(
++ __entry->intf_id = bundle->intf->interface_id;
++ __entry->id = bundle->id;
++ __entry->class = bundle->class;
++ __entry->num_cports = bundle->num_cports;
++ ),
++
++ TP_printk("intf_id=0x%02x id=%02x class=0x%02x num_cports=%zu",
++ __entry->intf_id, __entry->id, __entry->class,
++ __entry->num_cports)
++);
++
++#define DEFINE_BUNDLE_EVENT(name) \
++ DEFINE_EVENT(gb_bundle, name, \
++ TP_PROTO(struct gb_bundle *bundle), \
++ TP_ARGS(bundle))
++
++/*
++ * Occurs after a new bundle is successfully created.
++ */
++DEFINE_BUNDLE_EVENT(gb_bundle_create);
++
++/*
++ * Occurs when the last reference to a bundle has been dropped,
++ * before its resources are freed.
++ */
++DEFINE_BUNDLE_EVENT(gb_bundle_release);
++
++/*
++ * Occurs when a bundle is added to an interface when the interface
++ * is enabled.
++ */
++DEFINE_BUNDLE_EVENT(gb_bundle_add);
++
++/*
++ * Occurs when a registered bundle gets destroyed, normally at the
++ * time an interface is disabled.
++ */
++DEFINE_BUNDLE_EVENT(gb_bundle_destroy);
++
++#undef DEFINE_BUNDLE_EVENT
++
++DECLARE_EVENT_CLASS(gb_interface,
++
++ TP_PROTO(struct gb_interface *intf),
++
++ TP_ARGS(intf),
++
++ TP_STRUCT__entry(
++ __field(u8, module_id)
++ __field(u8, id) /* Interface id */
++ __field(u8, device_id)
++ __field(int, disconnected) /* bool */
++ __field(int, ejected) /* bool */
++ __field(int, active) /* bool */
++ __field(int, enabled) /* bool */
++ __field(int, mode_switch) /* bool */
++ ),
++
++ TP_fast_assign(
++ __entry->module_id = intf->module->module_id;
++ __entry->id = intf->interface_id;
++ __entry->device_id = intf->device_id;
++ __entry->disconnected = intf->disconnected;
++ __entry->ejected = intf->ejected;
++ __entry->active = intf->active;
++ __entry->enabled = intf->enabled;
++ __entry->mode_switch = intf->mode_switch;
++ ),
++
++ TP_printk("intf_id=%hhu device_id=%hhu module_id=%hhu D=%d J=%d A=%d E=%d M=%d",
++ __entry->id, __entry->device_id, __entry->module_id,
++ __entry->disconnected, __entry->ejected, __entry->active,
++ __entry->enabled, __entry->mode_switch)
++);
++
++#define DEFINE_INTERFACE_EVENT(name) \
++ DEFINE_EVENT(gb_interface, name, \
++ TP_PROTO(struct gb_interface *intf), \
++ TP_ARGS(intf))
++
++/*
++ * Occurs after a new interface is successfully created.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_create);
++
++/*
++ * Occurs after the last reference to an interface has been dropped.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_release);
++
++/*
++ * Occurs after an interface been registerd.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_add);
++
++/*
++ * Occurs when a registered interface gets deregisterd.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_del);
++
++/*
++ * Occurs when a registered interface has been successfully
++ * activated.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_activate);
++
++/*
++ * Occurs when an activated interface is being deactivated.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_deactivate);
++
++/*
++ * Occurs when an interface has been successfully enabled.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_enable);
++
++/*
++ * Occurs when an enabled interface is being disabled.
++ */
++DEFINE_INTERFACE_EVENT(gb_interface_disable);
++
++#undef DEFINE_INTERFACE_EVENT
++
++DECLARE_EVENT_CLASS(gb_module,
++
++ TP_PROTO(struct gb_module *module),
++
++ TP_ARGS(module),
++
++ TP_STRUCT__entry(
++ __field(int, hd_bus_id)
++ __field(u8, module_id)
++ __field(size_t, num_interfaces)
++ __field(int, disconnected) /* bool */
++ ),
++
++ TP_fast_assign(
++ __entry->hd_bus_id = module->hd->bus_id;
++ __entry->module_id = module->module_id;
++ __entry->num_interfaces = module->num_interfaces;
++ __entry->disconnected = module->disconnected;
++ ),
++
++ TP_printk("hd_bus_id=%d module_id=%hhu num_interfaces=%zu disconnected=%d",
++ __entry->hd_bus_id, __entry->module_id,
++ __entry->num_interfaces, __entry->disconnected)
++);
++
++#define DEFINE_MODULE_EVENT(name) \
++ DEFINE_EVENT(gb_module, name, \
++ TP_PROTO(struct gb_module *module), \
++ TP_ARGS(module))
++
++/*
++ * Occurs after a new module is successfully created, before
++ * creating any of its interfaces.
++ */
++DEFINE_MODULE_EVENT(gb_module_create);
++
++/*
++ * Occurs after the last reference to a module has been dropped.
++ */
++DEFINE_MODULE_EVENT(gb_module_release);
++
++/*
++ * Occurs after a module is successfully created, before registering
++ * any of its interfaces.
++ */
++DEFINE_MODULE_EVENT(gb_module_add);
++
++/*
++ * Occurs when a module is deleted, before deregistering its
++ * interfaces.
++ */
++DEFINE_MODULE_EVENT(gb_module_del);
++
++#undef DEFINE_MODULE_EVENT
++
++DECLARE_EVENT_CLASS(gb_host_device,
++
++ TP_PROTO(struct gb_host_device *hd),
++
++ TP_ARGS(hd),
++
++ TP_STRUCT__entry(
++ __field(int, bus_id)
++ __field(size_t, num_cports)
++ __field(size_t, buffer_size_max)
++ ),
++
++ TP_fast_assign(
++ __entry->bus_id = hd->bus_id;
++ __entry->num_cports = hd->num_cports;
++ __entry->buffer_size_max = hd->buffer_size_max;
++ ),
++
++ TP_printk("bus_id=%d num_cports=%zu mtu=%zu",
++ __entry->bus_id, __entry->num_cports,
++ __entry->buffer_size_max)
++);
++
++#define DEFINE_HD_EVENT(name) \
++ DEFINE_EVENT(gb_host_device, name, \
++ TP_PROTO(struct gb_host_device *hd), \
++ TP_ARGS(hd))
++
++/*
++ * Occurs after a new host device is successfully created, before
++ * its SVC has been set up.
++ */
++DEFINE_HD_EVENT(gb_hd_create);
++
++/*
++ * Occurs after the last reference to a host device has been
++ * dropped.
++ */
++DEFINE_HD_EVENT(gb_hd_release);
++
++/*
++ * Occurs after a new host device has been added, after the
++ * connection to its SVC has been enabled.
++ */
++DEFINE_HD_EVENT(gb_hd_add);
++
++/*
++ * Occurs when a host device is being disconnected from the AP USB
++ * host controller.
++ */
++DEFINE_HD_EVENT(gb_hd_del);
++
++/*
++ * Occurs when a host device has passed received data to the Greybus
++ * core, after it has been determined it is destined for a valid
++ * CPort.
++ */
++DEFINE_HD_EVENT(gb_hd_in);
++
++#undef DEFINE_HD_EVENT
++
++/*
++ * Occurs on a TimeSync synchronization event or a TimeSync ping event.
++ */
++TRACE_EVENT(gb_timesync_irq,
++
++ TP_PROTO(u8 ping, u8 strobe, u8 count, u64 frame_time),
++
++ TP_ARGS(ping, strobe, count, frame_time),
++
++ TP_STRUCT__entry(
++ __field(u8, ping)
++ __field(u8, strobe)
++ __field(u8, count)
++ __field(u64, frame_time)
++ ),
++
++ TP_fast_assign(
++ __entry->ping = ping;
++ __entry->strobe = strobe;
++ __entry->count = count;
++ __entry->frame_time = frame_time;
++ ),
++
++ TP_printk("%s %d/%d frame-time %llu\n",
++ __entry->ping ? "ping" : "strobe", __entry->strobe,
++ __entry->count, __entry->frame_time)
++);
++
++#endif /* _TRACE_GREYBUS_H */
++
++/* This part must be outside protection */
++#undef TRACE_INCLUDE_PATH
++#define TRACE_INCLUDE_PATH .
++
++/*
++ * TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal
++ */
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_FILE greybus_trace
++#include <trace/define_trace.h>
++
diff --git a/greybus_uart.patch b/greybus_uart.patch
new file mode 100644
index 00000000000000..6cbecc463c130e
--- /dev/null
+++ b/greybus_uart.patch
@@ -0,0 +1,1082 @@
+---
+ drivers/greybus/uart.c | 1075 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1075 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/uart.c
+@@ -0,0 +1,1075 @@
++/*
++ * UART driver for the Greybus "generic" UART module.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ *
++ * Heavily based on drivers/usb/class/cdc-acm.c and
++ * drivers/usb/serial/usb-serial.c.
++ */
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/mutex.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/idr.h>
++#include <linux/fs.h>
++#include <linux/kdev_t.h>
++#include <linux/kfifo.h>
++#include <linux/workqueue.h>
++#include <linux/completion.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++#define GB_NUM_MINORS 16 /* 16 is is more than enough */
++#define GB_NAME "ttyGB"
++
++#define GB_UART_WRITE_FIFO_SIZE PAGE_SIZE
++#define GB_UART_WRITE_ROOM_MARGIN 1 /* leave some space in fifo */
++#define GB_UART_FIRMWARE_CREDITS 4096
++#define GB_UART_CREDIT_WAIT_TIMEOUT_MSEC 10000
++
++struct gb_tty_line_coding {
++ __le32 rate;
++ __u8 format;
++ __u8 parity;
++ __u8 data_bits;
++ __u8 flow_control;
++};
++
++struct gb_tty {
++ struct gbphy_device *gbphy_dev;
++ struct tty_port port;
++ void *buffer;
++ size_t buffer_payload_max;
++ struct gb_connection *connection;
++ u16 cport_id;
++ unsigned int minor;
++ unsigned char clocal;
++ bool disconnected;
++ spinlock_t read_lock;
++ spinlock_t write_lock;
++ struct async_icount iocount;
++ struct async_icount oldcount;
++ wait_queue_head_t wioctl;
++ struct mutex mutex;
++ u8 ctrlin; /* input control lines */
++ u8 ctrlout; /* output control lines */
++ struct gb_tty_line_coding line_coding;
++ struct work_struct tx_work;
++ struct kfifo write_fifo;
++ bool close_pending;
++ unsigned int credits;
++ struct completion credits_complete;
++};
++
++static struct tty_driver *gb_tty_driver;
++static DEFINE_IDR(tty_minors);
++static DEFINE_MUTEX(table_lock);
++
++static int gb_uart_receive_data_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_tty *gb_tty = gb_connection_get_data(connection);
++ struct tty_port *port = &gb_tty->port;
++ struct gb_message *request = op->request;
++ struct gb_uart_recv_data_request *receive_data;
++ u16 recv_data_size;
++ int count;
++ unsigned long tty_flags = TTY_NORMAL;
++
++ if (request->payload_size < sizeof(*receive_data)) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "short receive-data request received (%zu < %zu)\n",
++ request->payload_size, sizeof(*receive_data));
++ return -EINVAL;
++ }
++
++ receive_data = op->request->payload;
++ recv_data_size = le16_to_cpu(receive_data->size);
++
++ if (recv_data_size != request->payload_size - sizeof(*receive_data)) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "malformed receive-data request received (%u != %zu)\n",
++ recv_data_size,
++ request->payload_size - sizeof(*receive_data));
++ return -EINVAL;
++ }
++
++ if (!recv_data_size)
++ return -EINVAL;
++
++ if (receive_data->flags) {
++ if (receive_data->flags & GB_UART_RECV_FLAG_BREAK)
++ tty_flags = TTY_BREAK;
++ else if (receive_data->flags & GB_UART_RECV_FLAG_PARITY)
++ tty_flags = TTY_PARITY;
++ else if (receive_data->flags & GB_UART_RECV_FLAG_FRAMING)
++ tty_flags = TTY_FRAME;
++
++ /* overrun is special, not associated with a char */
++ if (receive_data->flags & GB_UART_RECV_FLAG_OVERRUN)
++ tty_insert_flip_char(port, 0, TTY_OVERRUN);
++ }
++ count = tty_insert_flip_string_fixed_flag(port, receive_data->data,
++ tty_flags, recv_data_size);
++ if (count != recv_data_size) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "UART: RX 0x%08x bytes only wrote 0x%08x\n",
++ recv_data_size, count);
++ }
++ if (count)
++ tty_flip_buffer_push(port);
++ return 0;
++}
++
++static int gb_uart_serial_state_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_tty *gb_tty = gb_connection_get_data(connection);
++ struct gb_message *request = op->request;
++ struct gb_uart_serial_state_request *serial_state;
++
++ if (request->payload_size < sizeof(*serial_state)) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "short serial-state event received (%zu < %zu)\n",
++ request->payload_size, sizeof(*serial_state));
++ return -EINVAL;
++ }
++
++ serial_state = request->payload;
++ gb_tty->ctrlin = serial_state->control;
++
++ return 0;
++}
++
++static int gb_uart_receive_credits_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_tty *gb_tty = gb_connection_get_data(connection);
++ struct gb_message *request = op->request;
++ struct gb_uart_receive_credits_request *credit_request;
++ unsigned long flags;
++ unsigned int incoming_credits;
++ int ret = 0;
++
++ if (request->payload_size < sizeof(*credit_request)) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "short receive_credits event received (%zu < %zu)\n",
++ request->payload_size,
++ sizeof(*credit_request));
++ return -EINVAL;
++ }
++
++ credit_request = request->payload;
++ incoming_credits = le16_to_cpu(credit_request->count);
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ gb_tty->credits += incoming_credits;
++ if (gb_tty->credits > GB_UART_FIRMWARE_CREDITS) {
++ gb_tty->credits -= incoming_credits;
++ ret = -EINVAL;
++ }
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ if (ret) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "invalid number of incoming credits: %d\n",
++ incoming_credits);
++ return ret;
++ }
++
++ if (!gb_tty->close_pending)
++ schedule_work(&gb_tty->tx_work);
++
++ /*
++ * the port the tty layer may be waiting for credits
++ */
++ tty_port_tty_wakeup(&gb_tty->port);
++
++ if (gb_tty->credits == GB_UART_FIRMWARE_CREDITS)
++ complete(&gb_tty->credits_complete);
++
++ return ret;
++}
++
++static int gb_uart_request_handler(struct gb_operation *op)
++{
++ struct gb_connection *connection = op->connection;
++ struct gb_tty *gb_tty = gb_connection_get_data(connection);
++ int type = op->type;
++ int ret;
++
++ switch (type) {
++ case GB_UART_TYPE_RECEIVE_DATA:
++ ret = gb_uart_receive_data_handler(op);
++ break;
++ case GB_UART_TYPE_SERIAL_STATE:
++ ret = gb_uart_serial_state_handler(op);
++ break;
++ case GB_UART_TYPE_RECEIVE_CREDITS:
++ ret = gb_uart_receive_credits_handler(op);
++ break;
++ default:
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "unsupported unsolicited request: 0x%02x\n", type);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++static void gb_uart_tx_write_work(struct work_struct *work)
++{
++ struct gb_uart_send_data_request *request;
++ struct gb_tty *gb_tty;
++ unsigned long flags;
++ unsigned int send_size;
++ int ret;
++
++ gb_tty = container_of(work, struct gb_tty, tx_work);
++ request = gb_tty->buffer;
++
++ while (1) {
++ if (gb_tty->close_pending)
++ break;
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ send_size = gb_tty->buffer_payload_max;
++ if (send_size > gb_tty->credits)
++ send_size = gb_tty->credits;
++
++ send_size = kfifo_out_peek(&gb_tty->write_fifo,
++ &request->data[0],
++ send_size);
++ if (!send_size) {
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++ break;
++ }
++
++ gb_tty->credits -= send_size;
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ request->size = cpu_to_le16(send_size);
++ ret = gb_operation_sync(gb_tty->connection,
++ GB_UART_TYPE_SEND_DATA,
++ request, sizeof(*request) + send_size,
++ NULL, 0);
++ if (ret) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "send data error: %d\n", ret);
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ gb_tty->credits += send_size;
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++ if (!gb_tty->close_pending)
++ schedule_work(work);
++ return;
++ }
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ ret = kfifo_out(&gb_tty->write_fifo, &request->data[0],
++ send_size);
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ tty_port_tty_wakeup(&gb_tty->port);
++ }
++}
++
++static int send_line_coding(struct gb_tty *tty)
++{
++ struct gb_uart_set_line_coding_request request;
++
++ memcpy(&request, &tty->line_coding,
++ sizeof(tty->line_coding));
++ return gb_operation_sync(tty->connection, GB_UART_TYPE_SET_LINE_CODING,
++ &request, sizeof(request), NULL, 0);
++}
++
++static int send_control(struct gb_tty *gb_tty, u8 control)
++{
++ struct gb_uart_set_control_line_state_request request;
++
++ request.control = control;
++ return gb_operation_sync(gb_tty->connection,
++ GB_UART_TYPE_SET_CONTROL_LINE_STATE,
++ &request, sizeof(request), NULL, 0);
++}
++
++static int send_break(struct gb_tty *gb_tty, u8 state)
++{
++ struct gb_uart_set_break_request request;
++
++ if ((state != 0) && (state != 1)) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "invalid break state of %d\n", state);
++ return -EINVAL;
++ }
++
++ request.state = state;
++ return gb_operation_sync(gb_tty->connection, GB_UART_TYPE_SEND_BREAK,
++ &request, sizeof(request), NULL, 0);
++}
++
++static int gb_uart_wait_for_all_credits(struct gb_tty *gb_tty)
++{
++ int ret;
++
++ if (gb_tty->credits == GB_UART_FIRMWARE_CREDITS)
++ return 0;
++
++ ret = wait_for_completion_timeout(&gb_tty->credits_complete,
++ msecs_to_jiffies(GB_UART_CREDIT_WAIT_TIMEOUT_MSEC));
++ if (!ret) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "time out waiting for credits\n");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++static int gb_uart_flush(struct gb_tty *gb_tty, u8 flags)
++{
++ struct gb_uart_serial_flush_request request;
++
++ request.flags = flags;
++ return gb_operation_sync(gb_tty->connection, GB_UART_TYPE_FLUSH_FIFOS,
++ &request, sizeof(request), NULL, 0);
++}
++
++static struct gb_tty *get_gb_by_minor(unsigned minor)
++{
++ struct gb_tty *gb_tty;
++
++ mutex_lock(&table_lock);
++ gb_tty = idr_find(&tty_minors, minor);
++ if (gb_tty) {
++ mutex_lock(&gb_tty->mutex);
++ if (gb_tty->disconnected) {
++ mutex_unlock(&gb_tty->mutex);
++ gb_tty = NULL;
++ } else {
++ tty_port_get(&gb_tty->port);
++ mutex_unlock(&gb_tty->mutex);
++ }
++ }
++ mutex_unlock(&table_lock);
++ return gb_tty;
++}
++
++static int alloc_minor(struct gb_tty *gb_tty)
++{
++ int minor;
++
++ mutex_lock(&table_lock);
++ minor = idr_alloc(&tty_minors, gb_tty, 0, GB_NUM_MINORS, GFP_KERNEL);
++ mutex_unlock(&table_lock);
++ if (minor >= 0)
++ gb_tty->minor = minor;
++ return minor;
++}
++
++static void release_minor(struct gb_tty *gb_tty)
++{
++ int minor = gb_tty->minor;
++
++ gb_tty->minor = 0; /* Maybe should use an invalid value instead */
++ mutex_lock(&table_lock);
++ idr_remove(&tty_minors, minor);
++ mutex_unlock(&table_lock);
++}
++
++static int gb_tty_install(struct tty_driver *driver, struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty;
++ int retval;
++
++ gb_tty = get_gb_by_minor(tty->index);
++ if (!gb_tty)
++ return -ENODEV;
++
++ retval = tty_standard_install(driver, tty);
++ if (retval)
++ goto error;
++
++ tty->driver_data = gb_tty;
++ return 0;
++error:
++ tty_port_put(&gb_tty->port);
++ return retval;
++}
++
++static int gb_tty_open(struct tty_struct *tty, struct file *file)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ return tty_port_open(&gb_tty->port, tty, file);
++}
++
++static void gb_tty_close(struct tty_struct *tty, struct file *file)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ tty_port_close(&gb_tty->port, tty, file);
++}
++
++static void gb_tty_cleanup(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ tty_port_put(&gb_tty->port);
++}
++
++static void gb_tty_hangup(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ tty_port_hangup(&gb_tty->port);
++}
++
++static int gb_tty_write(struct tty_struct *tty, const unsigned char *buf,
++ int count)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ count = kfifo_in_spinlocked(&gb_tty->write_fifo, buf, count,
++ &gb_tty->write_lock);
++ if (count && !gb_tty->close_pending)
++ schedule_work(&gb_tty->tx_work);
++
++ return count;
++}
++
++static int gb_tty_write_room(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ unsigned long flags;
++ int room;
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ room = kfifo_avail(&gb_tty->write_fifo);
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ room -= GB_UART_WRITE_ROOM_MARGIN;
++ if (room < 0)
++ return 0;
++
++ return room;
++}
++
++static int gb_tty_chars_in_buffer(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ unsigned long flags;
++ int chars;
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ chars = kfifo_len(&gb_tty->write_fifo);
++ if (gb_tty->credits < GB_UART_FIRMWARE_CREDITS)
++ chars += GB_UART_FIRMWARE_CREDITS - gb_tty->credits;
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ return chars;
++}
++
++static int gb_tty_break_ctl(struct tty_struct *tty, int state)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ return send_break(gb_tty, state ? 1 : 0);
++}
++
++static void gb_tty_set_termios(struct tty_struct *tty,
++ struct ktermios *termios_old)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ struct ktermios *termios = &tty->termios;
++ struct gb_tty_line_coding newline;
++ u8 newctrl = gb_tty->ctrlout;
++
++ newline.rate = cpu_to_le32(tty_get_baud_rate(tty));
++ newline.format = termios->c_cflag & CSTOPB ?
++ GB_SERIAL_2_STOP_BITS : GB_SERIAL_1_STOP_BITS;
++ newline.parity = termios->c_cflag & PARENB ?
++ (termios->c_cflag & PARODD ? 1 : 2) +
++ (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
++
++ switch (termios->c_cflag & CSIZE) {
++ case CS5:
++ newline.data_bits = 5;
++ break;
++ case CS6:
++ newline.data_bits = 6;
++ break;
++ case CS7:
++ newline.data_bits = 7;
++ break;
++ case CS8:
++ default:
++ newline.data_bits = 8;
++ break;
++ }
++
++ /* FIXME: needs to clear unsupported bits in the termios */
++ gb_tty->clocal = ((termios->c_cflag & CLOCAL) != 0);
++
++ if (C_BAUD(tty) == B0) {
++ newline.rate = gb_tty->line_coding.rate;
++ newctrl &= ~(GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
++ } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) {
++ newctrl |= (GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
++ }
++
++ if (newctrl != gb_tty->ctrlout) {
++ gb_tty->ctrlout = newctrl;
++ send_control(gb_tty, newctrl);
++ }
++
++ if (C_CRTSCTS(tty) && C_BAUD(tty) != B0)
++ newline.flow_control |= GB_SERIAL_AUTO_RTSCTS_EN;
++ else
++ newline.flow_control &= ~GB_SERIAL_AUTO_RTSCTS_EN;
++
++ if (memcmp(&gb_tty->line_coding, &newline, sizeof(newline))) {
++ memcpy(&gb_tty->line_coding, &newline, sizeof(newline));
++ send_line_coding(gb_tty);
++ }
++}
++
++static int gb_tty_tiocmget(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ return (gb_tty->ctrlout & GB_UART_CTRL_DTR ? TIOCM_DTR : 0) |
++ (gb_tty->ctrlout & GB_UART_CTRL_RTS ? TIOCM_RTS : 0) |
++ (gb_tty->ctrlin & GB_UART_CTRL_DSR ? TIOCM_DSR : 0) |
++ (gb_tty->ctrlin & GB_UART_CTRL_RI ? TIOCM_RI : 0) |
++ (gb_tty->ctrlin & GB_UART_CTRL_DCD ? TIOCM_CD : 0) |
++ TIOCM_CTS;
++}
++
++static int gb_tty_tiocmset(struct tty_struct *tty, unsigned int set,
++ unsigned int clear)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ u8 newctrl = gb_tty->ctrlout;
++
++ set = (set & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
++ (set & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
++ clear = (clear & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
++ (clear & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
++
++ newctrl = (newctrl & ~clear) | set;
++ if (gb_tty->ctrlout == newctrl)
++ return 0;
++
++ gb_tty->ctrlout = newctrl;
++ return send_control(gb_tty, newctrl);
++}
++
++static void gb_tty_throttle(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ unsigned char stop_char;
++ int retval;
++
++ if (I_IXOFF(tty)) {
++ stop_char = STOP_CHAR(tty);
++ retval = gb_tty_write(tty, &stop_char, 1);
++ if (retval <= 0)
++ return;
++ }
++
++ if (tty->termios.c_cflag & CRTSCTS) {
++ gb_tty->ctrlout &= ~GB_UART_CTRL_RTS;
++ retval = send_control(gb_tty, gb_tty->ctrlout);
++ }
++}
++
++static void gb_tty_unthrottle(struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++ unsigned char start_char;
++ int retval;
++
++ if (I_IXOFF(tty)) {
++ start_char = START_CHAR(tty);
++ retval = gb_tty_write(tty, &start_char, 1);
++ if (retval <= 0)
++ return;
++ }
++
++ if (tty->termios.c_cflag & CRTSCTS) {
++ gb_tty->ctrlout |= GB_UART_CTRL_RTS;
++ retval = send_control(gb_tty, gb_tty->ctrlout);
++ }
++}
++
++static int get_serial_info(struct gb_tty *gb_tty,
++ struct serial_struct __user *info)
++{
++ struct serial_struct tmp;
++
++ if (!info)
++ return -EINVAL;
++
++ memset(&tmp, 0, sizeof(tmp));
++ tmp.flags = ASYNC_LOW_LATENCY | ASYNC_SKIP_TEST;
++ tmp.type = PORT_16550A;
++ tmp.line = gb_tty->minor;
++ tmp.xmit_fifo_size = 16;
++ tmp.baud_base = 9600;
++ tmp.close_delay = gb_tty->port.close_delay / 10;
++ tmp.closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
++ ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10;
++
++ if (copy_to_user(info, &tmp, sizeof(tmp)))
++ return -EFAULT;
++ return 0;
++}
++
++static int set_serial_info(struct gb_tty *gb_tty,
++ struct serial_struct __user *newinfo)
++{
++ struct serial_struct new_serial;
++ unsigned int closing_wait;
++ unsigned int close_delay;
++ int retval = 0;
++
++ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
++ return -EFAULT;
++
++ close_delay = new_serial.close_delay * 10;
++ closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
++ ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
++
++ mutex_lock(&gb_tty->port.mutex);
++ if (!capable(CAP_SYS_ADMIN)) {
++ if ((close_delay != gb_tty->port.close_delay) ||
++ (closing_wait != gb_tty->port.closing_wait))
++ retval = -EPERM;
++ else
++ retval = -EOPNOTSUPP;
++ } else {
++ gb_tty->port.close_delay = close_delay;
++ gb_tty->port.closing_wait = closing_wait;
++ }
++ mutex_unlock(&gb_tty->port.mutex);
++ return retval;
++}
++
++static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg)
++{
++ int retval = 0;
++ DECLARE_WAITQUEUE(wait, current);
++ struct async_icount old;
++ struct async_icount new;
++
++ if (!(arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD)))
++ return -EINVAL;
++
++ do {
++ spin_lock_irq(&gb_tty->read_lock);
++ old = gb_tty->oldcount;
++ new = gb_tty->iocount;
++ gb_tty->oldcount = new;
++ spin_unlock_irq(&gb_tty->read_lock);
++
++ if ((arg & TIOCM_DSR) && (old.dsr != new.dsr))
++ break;
++ if ((arg & TIOCM_CD) && (old.dcd != new.dcd))
++ break;
++ if ((arg & TIOCM_RI) && (old.rng != new.rng))
++ break;
++
++ add_wait_queue(&gb_tty->wioctl, &wait);
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule();
++ remove_wait_queue(&gb_tty->wioctl, &wait);
++ if (gb_tty->disconnected) {
++ if (arg & TIOCM_CD)
++ break;
++ retval = -ENODEV;
++ } else if (signal_pending(current)) {
++ retval = -ERESTARTSYS;
++ }
++ } while (!retval);
++
++ return retval;
++}
++
++static int get_serial_usage(struct gb_tty *gb_tty,
++ struct serial_icounter_struct __user *count)
++{
++ struct serial_icounter_struct icount;
++ int retval = 0;
++
++ memset(&icount, 0, sizeof(icount));
++ icount.dsr = gb_tty->iocount.dsr;
++ icount.rng = gb_tty->iocount.rng;
++ icount.dcd = gb_tty->iocount.dcd;
++ icount.frame = gb_tty->iocount.frame;
++ icount.overrun = gb_tty->iocount.overrun;
++ icount.parity = gb_tty->iocount.parity;
++ icount.brk = gb_tty->iocount.brk;
++
++ if (copy_to_user(count, &icount, sizeof(icount)) > 0)
++ retval = -EFAULT;
++
++ return retval;
++}
++
++static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
++ unsigned long arg)
++{
++ struct gb_tty *gb_tty = tty->driver_data;
++
++ switch (cmd) {
++ case TIOCGSERIAL:
++ return get_serial_info(gb_tty,
++ (struct serial_struct __user *)arg);
++ case TIOCSSERIAL:
++ return set_serial_info(gb_tty,
++ (struct serial_struct __user *)arg);
++ case TIOCMIWAIT:
++ return wait_serial_change(gb_tty, arg);
++ case TIOCGICOUNT:
++ return get_serial_usage(gb_tty,
++ (struct serial_icounter_struct __user *)arg);
++ }
++
++ return -ENOIOCTLCMD;
++}
++
++static void gb_tty_dtr_rts(struct tty_port *port, int on)
++{
++ struct gb_tty *gb_tty;
++ u8 newctrl;
++
++ gb_tty = container_of(port, struct gb_tty, port);
++ newctrl = gb_tty->ctrlout;
++
++ if (on)
++ newctrl |= (GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
++ else
++ newctrl &= ~(GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
++
++ gb_tty->ctrlout = newctrl;
++ send_control(gb_tty, newctrl);
++}
++
++static int gb_tty_port_activate(struct tty_port *port,
++ struct tty_struct *tty)
++{
++ struct gb_tty *gb_tty;
++
++ gb_tty = container_of(port, struct gb_tty, port);
++
++ return gbphy_runtime_get_sync(gb_tty->gbphy_dev);
++}
++
++static void gb_tty_port_shutdown(struct tty_port *port)
++{
++ struct gb_tty *gb_tty;
++ unsigned long flags;
++ int ret;
++
++ gb_tty = container_of(port, struct gb_tty, port);
++
++ gb_tty->close_pending = true;
++
++ cancel_work_sync(&gb_tty->tx_work);
++
++ spin_lock_irqsave(&gb_tty->write_lock, flags);
++ kfifo_reset_out(&gb_tty->write_fifo);
++ spin_unlock_irqrestore(&gb_tty->write_lock, flags);
++
++ if (gb_tty->credits == GB_UART_FIRMWARE_CREDITS)
++ goto out;
++
++ ret = gb_uart_flush(gb_tty, GB_SERIAL_FLAG_FLUSH_TRANSMITTER);
++ if (ret) {
++ dev_err(&gb_tty->gbphy_dev->dev,
++ "error flushing transmitter: %d\n", ret);
++ }
++
++ gb_uart_wait_for_all_credits(gb_tty);
++
++out:
++ gb_tty->close_pending = false;
++
++ gbphy_runtime_put_autosuspend(gb_tty->gbphy_dev);
++}
++
++static const struct tty_operations gb_ops = {
++ .install = gb_tty_install,
++ .open = gb_tty_open,
++ .close = gb_tty_close,
++ .cleanup = gb_tty_cleanup,
++ .hangup = gb_tty_hangup,
++ .write = gb_tty_write,
++ .write_room = gb_tty_write_room,
++ .ioctl = gb_tty_ioctl,
++ .throttle = gb_tty_throttle,
++ .unthrottle = gb_tty_unthrottle,
++ .chars_in_buffer = gb_tty_chars_in_buffer,
++ .break_ctl = gb_tty_break_ctl,
++ .set_termios = gb_tty_set_termios,
++ .tiocmget = gb_tty_tiocmget,
++ .tiocmset = gb_tty_tiocmset,
++};
++
++static struct tty_port_operations gb_port_ops = {
++ .dtr_rts = gb_tty_dtr_rts,
++ .activate = gb_tty_port_activate,
++ .shutdown = gb_tty_port_shutdown,
++};
++
++static int gb_uart_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ size_t max_payload;
++ struct gb_tty *gb_tty;
++ struct device *tty_dev;
++ int retval;
++ int minor;
++
++ gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL);
++ if (!gb_tty)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ gb_uart_request_handler);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto exit_tty_free;
++ }
++
++ max_payload = gb_operation_get_payload_size_max(connection);
++ if (max_payload < sizeof(struct gb_uart_send_data_request)) {
++ retval = -EINVAL;
++ goto exit_connection_destroy;
++ }
++
++ gb_tty->buffer_payload_max = max_payload -
++ sizeof(struct gb_uart_send_data_request);
++
++ gb_tty->buffer = kzalloc(gb_tty->buffer_payload_max, GFP_KERNEL);
++ if (!gb_tty->buffer) {
++ retval = -ENOMEM;
++ goto exit_connection_destroy;
++ }
++
++ INIT_WORK(&gb_tty->tx_work, gb_uart_tx_write_work);
++
++ retval = kfifo_alloc(&gb_tty->write_fifo, GB_UART_WRITE_FIFO_SIZE,
++ GFP_KERNEL);
++ if (retval)
++ goto exit_buf_free;
++
++ gb_tty->credits = GB_UART_FIRMWARE_CREDITS;
++ init_completion(&gb_tty->credits_complete);
++
++ minor = alloc_minor(gb_tty);
++ if (minor < 0) {
++ if (minor == -ENOSPC) {
++ dev_err(&connection->bundle->dev,
++ "no more free minor numbers\n");
++ retval = -ENODEV;
++ } else {
++ retval = minor;
++ }
++ goto exit_kfifo_free;
++ }
++
++ gb_tty->minor = minor;
++ spin_lock_init(&gb_tty->write_lock);
++ spin_lock_init(&gb_tty->read_lock);
++ init_waitqueue_head(&gb_tty->wioctl);
++ mutex_init(&gb_tty->mutex);
++
++ tty_port_init(&gb_tty->port);
++ gb_tty->port.ops = &gb_port_ops;
++
++ gb_tty->connection = connection;
++ gb_tty->gbphy_dev = gbphy_dev;
++ gb_connection_set_data(connection, gb_tty);
++ gb_gbphy_set_data(gbphy_dev, gb_tty);
++
++ retval = gb_connection_enable_tx(connection);
++ if (retval)
++ goto exit_release_minor;
++
++ send_control(gb_tty, gb_tty->ctrlout);
++
++ /* initialize the uart to be 9600n81 */
++ gb_tty->line_coding.rate = cpu_to_le32(9600);
++ gb_tty->line_coding.format = GB_SERIAL_1_STOP_BITS;
++ gb_tty->line_coding.parity = GB_SERIAL_NO_PARITY;
++ gb_tty->line_coding.data_bits = 8;
++ send_line_coding(gb_tty);
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto exit_connection_disable;
++
++ tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor,
++ &gbphy_dev->dev);
++ if (IS_ERR(tty_dev)) {
++ retval = PTR_ERR(tty_dev);
++ goto exit_connection_disable;
++ }
++
++ gbphy_runtime_put_autosuspend(gbphy_dev);
++ return 0;
++
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_release_minor:
++ release_minor(gb_tty);
++exit_kfifo_free:
++ kfifo_free(&gb_tty->write_fifo);
++exit_buf_free:
++ kfree(gb_tty->buffer);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_tty_free:
++ kfree(gb_tty);
++
++ return retval;
++}
++
++static void gb_uart_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_tty *gb_tty = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = gb_tty->connection;
++ struct tty_struct *tty;
++ int ret;
++
++ ret = gbphy_runtime_get_sync(gbphy_dev);
++ if (ret)
++ gbphy_runtime_get_noresume(gbphy_dev);
++
++ mutex_lock(&gb_tty->mutex);
++ gb_tty->disconnected = true;
++
++ wake_up_all(&gb_tty->wioctl);
++ mutex_unlock(&gb_tty->mutex);
++
++ tty = tty_port_tty_get(&gb_tty->port);
++ if (tty) {
++ tty_vhangup(tty);
++ tty_kref_put(tty);
++ }
++
++ gb_connection_disable_rx(connection);
++ tty_unregister_device(gb_tty_driver, gb_tty->minor);
++
++ /* FIXME - free transmit / receive buffers */
++
++ gb_connection_disable(connection);
++ tty_port_destroy(&gb_tty->port);
++ gb_connection_destroy(connection);
++ release_minor(gb_tty);
++ kfifo_free(&gb_tty->write_fifo);
++ kfree(gb_tty->buffer);
++ kfree(gb_tty);
++}
++
++static int gb_tty_init(void)
++{
++ int retval = 0;
++
++ gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, 0);
++ if (IS_ERR(gb_tty_driver)) {
++ pr_err("Can not allocate tty driver\n");
++ retval = -ENOMEM;
++ goto fail_unregister_dev;
++ }
++
++ gb_tty_driver->driver_name = "gb";
++ gb_tty_driver->name = GB_NAME;
++ gb_tty_driver->major = 0;
++ gb_tty_driver->minor_start = 0;
++ gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
++ gb_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
++ gb_tty_driver->init_termios = tty_std_termios;
++ gb_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++ tty_set_operations(gb_tty_driver, &gb_ops);
++
++ retval = tty_register_driver(gb_tty_driver);
++ if (retval) {
++ pr_err("Can not register tty driver: %d\n", retval);
++ goto fail_put_gb_tty;
++ }
++
++ return 0;
++
++fail_put_gb_tty:
++ put_tty_driver(gb_tty_driver);
++fail_unregister_dev:
++ return retval;
++}
++
++static void gb_tty_exit(void)
++{
++ tty_unregister_driver(gb_tty_driver);
++ put_tty_driver(gb_tty_driver);
++ idr_destroy(&tty_minors);
++}
++
++static const struct gbphy_device_id gb_uart_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_UART) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_uart_id_table);
++
++static struct gbphy_driver uart_driver = {
++ .name = "uart",
++ .probe = gb_uart_probe,
++ .remove = gb_uart_remove,
++ .id_table = gb_uart_id_table,
++};
++
++static int gb_uart_driver_init(void)
++{
++ int ret;
++
++ ret = gb_tty_init();
++ if (ret)
++ return ret;
++
++ ret = gb_gbphy_register(&uart_driver);
++ if (ret) {
++ gb_tty_exit();
++ return ret;
++ }
++
++ return 0;
++}
++module_init(gb_uart_driver_init);
++
++static void gb_uart_driver_exit(void)
++{
++ gb_gbphy_deregister(&uart_driver);
++ gb_tty_exit();
++}
++
++module_exit(gb_uart_driver_exit);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_usb.patch b/greybus_usb.patch
new file mode 100644
index 00000000000000..c2719d11714126
--- /dev/null
+++ b/greybus_usb.patch
@@ -0,0 +1,254 @@
+---
+ drivers/greybus/usb.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 247 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/usb.c
+@@ -0,0 +1,247 @@
++/*
++ * USB host driver for the Greybus "generic" USB module.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/usb.h>
++#include <linux/usb/hcd.h>
++
++#include "greybus.h"
++#include "gbphy.h"
++
++/* Greybus USB request types */
++#define GB_USB_TYPE_HCD_START 0x02
++#define GB_USB_TYPE_HCD_STOP 0x03
++#define GB_USB_TYPE_HUB_CONTROL 0x04
++
++struct gb_usb_hub_control_request {
++ __le16 typeReq;
++ __le16 wValue;
++ __le16 wIndex;
++ __le16 wLength;
++};
++
++struct gb_usb_hub_control_response {
++ u8 buf[0];
++};
++
++struct gb_usb_device {
++ struct gb_connection *connection;
++ struct gbphy_device *gbphy_dev;
++};
++
++static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
++{
++ return (struct gb_usb_device *)hcd->hcd_priv;
++}
++
++static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
++{
++ return container_of((void *)dev, struct usb_hcd, hcd_priv);
++}
++
++static void hcd_stop(struct usb_hcd *hcd)
++{
++ struct gb_usb_device *dev = to_gb_usb_device(hcd);
++ int ret;
++
++ ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
++ NULL, 0, NULL, 0);
++ if (ret)
++ dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
++}
++
++static int hcd_start(struct usb_hcd *hcd)
++{
++ struct usb_bus *bus = hcd_to_bus(hcd);
++ struct gb_usb_device *dev = to_gb_usb_device(hcd);
++ int ret;
++
++ ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
++ NULL, 0, NULL, 0);
++ if (ret) {
++ dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
++ return ret;
++ }
++
++ hcd->state = HC_STATE_RUNNING;
++ if (bus->root_hub)
++ usb_hcd_resume_root_hub(hcd);
++ return 0;
++}
++
++static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
++{
++ return -ENXIO;
++}
++
++static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
++{
++ return -ENXIO;
++}
++
++static int get_frame_number(struct usb_hcd *hcd)
++{
++ return 0;
++}
++
++static int hub_status_data(struct usb_hcd *hcd, char *buf)
++{
++ return 0;
++}
++
++static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
++ char *buf, u16 wLength)
++{
++ struct gb_usb_device *dev = to_gb_usb_device(hcd);
++ struct gb_operation *operation;
++ struct gb_usb_hub_control_request *request;
++ struct gb_usb_hub_control_response *response;
++ size_t response_size;
++ int ret;
++
++ /* FIXME: handle unspecified lengths */
++ response_size = sizeof(*response) + wLength;
++
++ operation = gb_operation_create(dev->connection,
++ GB_USB_TYPE_HUB_CONTROL,
++ sizeof(*request),
++ response_size,
++ GFP_KERNEL);
++ if (!operation)
++ return -ENOMEM;
++
++ request = operation->request->payload;
++ request->typeReq = cpu_to_le16(typeReq);
++ request->wValue = cpu_to_le16(wValue);
++ request->wIndex = cpu_to_le16(wIndex);
++ request->wLength = cpu_to_le16(wLength);
++
++ ret = gb_operation_request_send_sync(operation);
++ if (ret)
++ goto out;
++
++ if (wLength) {
++ /* Greybus core has verified response size */
++ response = operation->response->payload;
++ memcpy(buf, response->buf, wLength);
++ }
++out:
++ gb_operation_put(operation);
++
++ return ret;
++}
++
++static struct hc_driver usb_gb_hc_driver = {
++ .description = "greybus-hcd",
++ .product_desc = "Greybus USB Host Controller",
++ .hcd_priv_size = sizeof(struct gb_usb_device),
++
++ .flags = HCD_USB2,
++
++ .start = hcd_start,
++ .stop = hcd_stop,
++
++ .urb_enqueue = urb_enqueue,
++ .urb_dequeue = urb_dequeue,
++
++ .get_frame_number = get_frame_number,
++ .hub_status_data = hub_status_data,
++ .hub_control = hub_control,
++};
++
++static int gb_usb_probe(struct gbphy_device *gbphy_dev,
++ const struct gbphy_device_id *id)
++{
++ struct gb_connection *connection;
++ struct device *dev = &gbphy_dev->dev;
++ struct gb_usb_device *gb_usb_dev;
++ struct usb_hcd *hcd;
++ int retval;
++
++ hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ connection = gb_connection_create(gbphy_dev->bundle,
++ le16_to_cpu(gbphy_dev->cport_desc->id),
++ NULL);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto exit_usb_put;
++ }
++
++ gb_usb_dev = to_gb_usb_device(hcd);
++ gb_usb_dev->connection = connection;
++ gb_connection_set_data(connection, gb_usb_dev);
++ gb_usb_dev->gbphy_dev = gbphy_dev;
++ gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
++
++ hcd->has_tt = 1;
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto exit_connection_destroy;
++
++ /*
++ * FIXME: The USB bridged-PHY protocol driver depends on changes to
++ * USB core which are not yet upstream.
++ *
++ * Disable for now.
++ */
++ if (1) {
++ dev_warn(dev, "USB protocol disabled\n");
++ retval = -EPROTONOSUPPORT;
++ goto exit_connection_disable;
++ }
++
++ retval = usb_add_hcd(hcd, 0, 0);
++ if (retval)
++ goto exit_connection_disable;
++
++ return 0;
++
++exit_connection_disable:
++ gb_connection_disable(connection);
++exit_connection_destroy:
++ gb_connection_destroy(connection);
++exit_usb_put:
++ usb_put_hcd(hcd);
++
++ return retval;
++}
++
++static void gb_usb_remove(struct gbphy_device *gbphy_dev)
++{
++ struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
++ struct gb_connection *connection = gb_usb_dev->connection;
++ struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
++
++ usb_remove_hcd(hcd);
++ gb_connection_disable(connection);
++ gb_connection_destroy(connection);
++ usb_put_hcd(hcd);
++}
++
++static const struct gbphy_device_id gb_usb_id_table[] = {
++ { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
++ { },
++};
++MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
++
++static struct gbphy_driver usb_driver = {
++ .name = "usb",
++ .probe = gb_usb_probe,
++ .remove = gb_usb_remove,
++ .id_table = gb_usb_id_table,
++};
++
++module_gbphy_driver(usb_driver);
++MODULE_LICENSE("GPL v2");
diff --git a/greybus_vibrator.patch b/greybus_vibrator.patch
new file mode 100644
index 00000000000000..083b9fdf368efa
--- /dev/null
+++ b/greybus_vibrator.patch
@@ -0,0 +1,256 @@
+---
+ drivers/greybus/vibrator.c | 249 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 249 insertions(+)
+
+--- /dev/null
++++ b/drivers/greybus/vibrator.c
+@@ -0,0 +1,249 @@
++/*
++ * Greybus Vibrator protocol driver.
++ *
++ * Copyright 2014 Google Inc.
++ * Copyright 2014 Linaro Ltd.
++ *
++ * Released under the GPLv2 only.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/kdev_t.h>
++#include <linux/idr.h>
++#include <linux/pm_runtime.h>
++
++#include "greybus.h"
++
++struct gb_vibrator_device {
++ struct gb_connection *connection;
++ struct device *dev;
++ int minor; /* vibrator minor number */
++ struct delayed_work delayed_work;
++};
++
++/* Greybus Vibrator operation types */
++#define GB_VIBRATOR_TYPE_ON 0x02
++#define GB_VIBRATOR_TYPE_OFF 0x03
++
++static int turn_off(struct gb_vibrator_device *vib)
++{
++ struct gb_bundle *bundle = vib->connection->bundle;
++ int ret;
++
++ ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF,
++ NULL, 0, NULL, 0);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return ret;
++}
++
++static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
++{
++ struct gb_bundle *bundle = vib->connection->bundle;
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ return ret;
++
++ /* Vibrator was switched ON earlier */
++ if (cancel_delayed_work_sync(&vib->delayed_work))
++ turn_off(vib);
++
++ ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON,
++ NULL, 0, NULL, 0);
++ if (ret) {
++ gb_pm_runtime_put_autosuspend(bundle);
++ return ret;
++ }
++
++ schedule_delayed_work(&vib->delayed_work, msecs_to_jiffies(timeout_ms));
++
++ return 0;
++}
++
++static void gb_vibrator_worker(struct work_struct *work)
++{
++ struct delayed_work *delayed_work = to_delayed_work(work);
++ struct gb_vibrator_device *vib =
++ container_of(delayed_work, struct gb_vibrator_device, delayed_work);
++
++ turn_off(vib);
++}
++
++static ssize_t timeout_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct gb_vibrator_device *vib = dev_get_drvdata(dev);
++ unsigned long val;
++ int retval;
++
++ retval = kstrtoul(buf, 10, &val);
++ if (retval < 0) {
++ dev_err(dev, "could not parse timeout value %d\n", retval);
++ return retval;
++ }
++
++ if (val)
++ retval = turn_on(vib, (u16)val);
++ else
++ retval = turn_off(vib);
++ if (retval)
++ return retval;
++
++ return count;
++}
++static DEVICE_ATTR_WO(timeout);
++
++static struct attribute *vibrator_attrs[] = {
++ &dev_attr_timeout.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(vibrator);
++
++static struct class vibrator_class = {
++ .name = "vibrator",
++ .owner = THIS_MODULE,
++ .dev_groups = vibrator_groups,
++};
++
++static DEFINE_IDA(minors);
++
++static int gb_vibrator_probe(struct gb_bundle *bundle,
++ const struct greybus_bundle_id *id)
++{
++ struct greybus_descriptor_cport *cport_desc;
++ struct gb_connection *connection;
++ struct gb_vibrator_device *vib;
++ struct device *dev;
++ int retval;
++
++ if (bundle->num_cports != 1)
++ return -ENODEV;
++
++ cport_desc = &bundle->cport_desc[0];
++ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_VIBRATOR)
++ return -ENODEV;
++
++ vib = kzalloc(sizeof(*vib), GFP_KERNEL);
++ if (!vib)
++ return -ENOMEM;
++
++ connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
++ NULL);
++ if (IS_ERR(connection)) {
++ retval = PTR_ERR(connection);
++ goto err_free_vib;
++ }
++ gb_connection_set_data(connection, vib);
++
++ vib->connection = connection;
++
++ greybus_set_drvdata(bundle, vib);
++
++ retval = gb_connection_enable(connection);
++ if (retval)
++ goto err_connection_destroy;
++
++ /*
++ * For now we create a device in sysfs for the vibrator, but odds are
++ * there is a "real" device somewhere in the kernel for this, but I
++ * can't find it at the moment...
++ */
++ vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
++ if (vib->minor < 0) {
++ retval = vib->minor;
++ goto err_connection_disable;
++ }
++ dev = device_create(&vibrator_class, &bundle->dev,
++ MKDEV(0, 0), vib, "vibrator%d", vib->minor);
++ if (IS_ERR(dev)) {
++ retval = -EINVAL;
++ goto err_ida_remove;
++ }
++ vib->dev = dev;
++
++ INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker);
++
++ gb_pm_runtime_put_autosuspend(bundle);
++
++ return 0;
++
++err_ida_remove:
++ ida_simple_remove(&minors, vib->minor);
++err_connection_disable:
++ gb_connection_disable(connection);
++err_connection_destroy:
++ gb_connection_destroy(connection);
++err_free_vib:
++ kfree(vib);
++
++ return retval;
++}
++
++static void gb_vibrator_disconnect(struct gb_bundle *bundle)
++{
++ struct gb_vibrator_device *vib = greybus_get_drvdata(bundle);
++ int ret;
++
++ ret = gb_pm_runtime_get_sync(bundle);
++ if (ret)
++ gb_pm_runtime_get_noresume(bundle);
++
++ if (cancel_delayed_work_sync(&vib->delayed_work))
++ turn_off(vib);
++
++ device_unregister(vib->dev);
++ ida_simple_remove(&minors, vib->minor);
++ gb_connection_disable(vib->connection);
++ gb_connection_destroy(vib->connection);
++ kfree(vib);
++}
++
++static const struct greybus_bundle_id gb_vibrator_id_table[] = {
++ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
++ { }
++};
++MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
++
++static struct greybus_driver gb_vibrator_driver = {
++ .name = "vibrator",
++ .probe = gb_vibrator_probe,
++ .disconnect = gb_vibrator_disconnect,
++ .id_table = gb_vibrator_id_table,
++};
++
++static __init int gb_vibrator_init(void)
++{
++ int retval;
++
++ retval = class_register(&vibrator_class);
++ if (retval)
++ return retval;
++
++ retval = greybus_register(&gb_vibrator_driver);
++ if (retval)
++ goto err_class_unregister;
++
++ return 0;
++
++err_class_unregister:
++ class_unregister(&vibrator_class);
++
++ return retval;
++}
++module_init(gb_vibrator_init);
++
++static __exit void gb_vibrator_exit(void)
++{
++ greybus_deregister(&gb_vibrator_driver);
++ class_unregister(&vibrator_class);
++ ida_destroy(&minors);
++}
++module_exit(gb_vibrator_exit);
++
++MODULE_LICENSE("GPL v2");
diff --git a/series b/series
index 29bf77912579ad..9079e28652a1b9 100644
--- a/series
+++ b/series
@@ -1,57 +1,109 @@
-usb-core-add-missing-license-information.patch
-
-# broken patch!
-
-csdio2.patch
-#input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch
-#defer-input-nodes-and-led-support
-#input-xpad-move-the-input-device-creation-to-a-new-function.patch
-#input-xpad-set-the-correct-led-number.patch
-#input-xpad-disconnect-all-wireless-controllers-at-init.patch
-#input-xpad-handle-present-and-gone-correctly.patch
-#input-xpad-properly-name-the-led-class-devices.patch
-
-
-staging-exfat-add-filesystem-to-drivers-staging-exfat.patch
-staging-exfat-add-filesystem-to-the-build.patch
-staging-exfat-include-aio.h.patch
-staging-exfat-hlist_for_each-api-change.patch
-staging-exfat-truncage_pagecache-api-change.patch
-staging-exfat-readdir-to-iterate-change.patch
-staging-exfat-kuid-fixes.patch
-
-
-# patches already in my git trees, but still here so I don't loose them.
-
-# usb DEBUG cleanups
-
-
-# My specific stuff, at the top to make it easier to work stuff below.
-
-# driver core attribute cleanup work
-
-# dev_groups to struct class work
-
-
-simulate-fake-fn-key-on-ps-2-keyboards-w-o-one-eg.-chromebook-pixel.patch
-
-#gregkh/gkh-version.patch
-
-driver-core-remove-struct-bus_type.dev_attrs.patch
-
-p18.patch
-p19.patch
-p20.patch
-p21.patch
-p22.patch
-p23.patch
-p24.patch
-p25.patch
-p26.patch
-p27.patch
-p28.patch
-p29.patch
-
-qlcnic_sysfs.patch
-
-d01.patch
+greybus_protocol.patch
+greybus_interface.patch
+greybus_operations.patch
+greybus_hd.patch
+greybus_trace.patch
+greybus_svc.patch
+greybus_core.patch
+
+greybus_bootrom.patch
+greybus_firmware.patch
+
+greybus_audio.patch
+greybus_camera.patch
+greybus_es2.patch
+greybus_hid.patch
+greybus_light.patch
+greybus_log.patch
+greybus_loopback.patch
+greybus_power.patch
+greybus_raw.patch
+greybus_timesync.patch
+greybus_vibrator.patch
+
+greybus_arche.patch
+
+greybus_gbphy.patch
+greybus_gpio.patch
+greybus_i2c.patch
+greybus_pwm.patch
+greybus_sdio.patch
+greybus_spi.patch
+greybus_uart.patch
+greybus_usb.patch
+
+greybus_tools.patch
+greybus_docs.patch
+greybus_build.patch
+
+
+#
+#usb-core-add-missing-license-information.patch
+#
+## broken patch!
+#
+#csdio2.patch
+##input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch
+##defer-input-nodes-and-led-support
+##input-xpad-move-the-input-device-creation-to-a-new-function.patch
+##input-xpad-set-the-correct-led-number.patch
+##input-xpad-disconnect-all-wireless-controllers-at-init.patch
+##input-xpad-handle-present-and-gone-correctly.patch
+##input-xpad-properly-name-the-led-class-devices.patch
+#
+#
+#staging-exfat-add-filesystem-to-drivers-staging-exfat.patch
+#staging-exfat-add-filesystem-to-the-build.patch
+#staging-exfat-include-aio.h.patch
+#staging-exfat-hlist_for_each-api-change.patch
+#staging-exfat-truncage_pagecache-api-change.patch
+#staging-exfat-readdir-to-iterate-change.patch
+#staging-exfat-kuid-fixes.patch
+#
+#
+## patches already in my git trees, but still here so I don't loose them.
+#
+## usb DEBUG cleanups
+#
+#
+## My specific stuff, at the top to make it easier to work stuff below.
+#
+## driver core attribute cleanup work
+#
+## dev_groups to struct class work
+#
+#
+#simulate-fake-fn-key-on-ps-2-keyboards-w-o-one-eg.-chromebook-pixel.patch
+#
+##gregkh/gkh-version.patch
+#
+#driver-core-remove-struct-bus_type.dev_attrs.patch
+#
+#p18.patch
+#p19.patch
+#p20.patch
+#p21.patch
+#p22.patch
+#p23.patch
+#p24.patch
+#p25.patch
+#p26.patch
+#p27.patch
+#p28.patch
+#p29.patch
+#
+#qlcnic_sysfs.patch
+#
+#d01.patch
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#