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;