summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVaibhav Hiremath <vaibhav.hiremath@linaro.org>2016-07-28 13:47:37 +0530
committerGreg Kroah-Hartman <gregkh@google.com>2016-08-03 15:45:08 +0200
commit921dbe52b40b2573d9a0e8337c768930bef25fb4 (patch)
treefa2a0732c93159eaf6a83db1872982bd1bda2685
parent8ef0b5383110977d81746cd0b09c3877d51c3a67 (diff)
downloadlinux-921dbe52b40b2573d9a0e8337c768930bef25fb4.tar.bz2
greybus: arche-platform: Add support for SPI bus sharing for Mihi
In case of Mihi, SPI bus is shared between APB1 and APB2 SPI ROMs, so their FW flashing must be sequential and arche-platform driver should make sure that they are mutual exclusive in nature. So this patch adds certain restrictions to the user of the arche-platform driver, - User can no longer flash APB1 and APB2 SPI ROM in parallel - SPI bus becomes an resource, so user must claim it by moving respective APB device into FW_FLASHING mode and release it by exiting FW_FLASHING mode. User can exit FW_FLASHING mode by switching to any other modes (ACTIVE, OFF, STANDBY). - If APB1 is in FW_FLASHING mode, APB2 can no longer enter into FW_FLASHING mode. User will get -EBUSY. Having said that, while APB1 is into FW_FLASHING mode, APB2 can independently boot from its own SPI ROM. Testing Done: Tested by simulating usecase on EVT2. - Made sure that APB1 and APB2 FW_FLASHING mode is mutual exclusive in nature. Confirmed that an attempt on second device return -EBUSY. - Added simulating code, where printed state of dummy gpio for spi-en and verified that it shows right pin status for both APBs Signed-off-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
-rw-r--r--drivers/staging/greybus/arche-apb-ctrl.c43
-rw-r--r--drivers/staging/greybus/arche-platform.c25
2 files changed, 50 insertions, 18 deletions
diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c
index 049d496a41f4..59d9d422cf04 100644
--- a/drivers/staging/greybus/arche-apb-ctrl.c
+++ b/drivers/staging/greybus/arche-apb-ctrl.c
@@ -42,6 +42,10 @@ struct arche_apb_ctrl_drvdata {
struct pinctrl *pinctrl;
struct pinctrl_state *pin_default;
+
+ /* V2: SPI Bus control */
+ int spi_en_gpio;
+ bool spi_en_polarity_high;
};
/*
@@ -73,6 +77,10 @@ static int coldboot_seq(struct platform_device *pdev)
/* 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);
@@ -128,6 +136,23 @@ static int fw_flashing_seq(struct platform_device *pdev)
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;
@@ -137,6 +162,7 @@ static int fw_flashing_seq(struct platform_device *pdev)
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)
@@ -147,6 +173,10 @@ static int standby_boot_seq(struct platform_device *pdev)
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
*
@@ -162,11 +192,16 @@ static int standby_boot_seq(struct platform_device *pdev)
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);
@@ -369,6 +404,14 @@ static int apb_ctrl_get_devtree_data(struct platform_device *pdev,
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;
}
diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c
index adec1fdcb5bb..9d9048e6aed3 100644
--- a/drivers/staging/greybus/arche-platform.c
+++ b/drivers/staging/greybus/arche-platform.c
@@ -215,18 +215,6 @@ static int apb_cold_boot(struct device *dev, void *data)
return 0;
}
-static int apb_fw_flashing_state(struct device *dev, void *data)
-{
- int ret;
-
- ret = apb_ctrl_fw_flashing(dev);
- if (ret)
- dev_warn(dev, "failed to switch to fw flashing state\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);
@@ -485,17 +473,18 @@ retry:
if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
goto exit;
- /* First we want to make sure we power off everything
- * and then enter FW flashing state */
- device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
-
+ /*
+ * 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;
-
- device_for_each_child(arche_pdata->dev, NULL, apb_fw_flashing_state);
} else {
dev_err(arche_pdata->dev, "unknown state\n");
ret = -EINVAL;