[PATCH v4 4/4] mmc: sdhci-of-arasan: Enable UHS-1 support for Keem Bay SOC

Adrian Hunter adrian.hunter at intel.com
Thu Oct 8 06:58:31 EDT 2020


On 8/10/20 12:27 pm, Ulf Hansson wrote:
> On Thu, 8 Oct 2020 at 04:12, <muhammad.husaini.zulkifli at intel.com> wrote:
>>
>> From: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli at intel.com>
>>
>> Voltage switching sequence is needed to support UHS-1 interface.
>> There are 2 places to control the voltage.
>> 1) By setting the AON register using firmware driver calling
>> system-level platform management layer (SMC) to set the register.
>> 2) By controlling the GPIO expander value to drive either 1.8V or 3.3V
>> for power mux input.
>>
>> Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli at intel.com>
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko at intel.com>
>> Reviewed-by: Adrian Hunter <adrian.hunter at intel.com>
>> ---
>>  drivers/mmc/host/sdhci-of-arasan.c | 126 +++++++++++++++++++++++++++++
>>  1 file changed, 126 insertions(+)
>>
>> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
>> index 46aea6516133..ea2467b0073d 100644
>> --- a/drivers/mmc/host/sdhci-of-arasan.c
>> +++ b/drivers/mmc/host/sdhci-of-arasan.c
>> @@ -16,6 +16,7 @@
>>   */
>>
>>  #include <linux/clk-provider.h>
>> +#include <linux/gpio/consumer.h>
>>  #include <linux/mfd/syscon.h>
>>  #include <linux/module.h>
>>  #include <linux/of_device.h>
>> @@ -23,6 +24,7 @@
>>  #include <linux/regmap.h>
>>  #include <linux/of.h>
>>  #include <linux/firmware/xlnx-zynqmp.h>
>> +#include <linux/firmware/intel/keembay_firmware.h>
>>
>>  #include "cqhci.h"
>>  #include "sdhci-pltfm.h"
>> @@ -136,6 +138,7 @@ struct sdhci_arasan_clk_data {
>>   * @soc_ctl_base:      Pointer to regmap for syscon for soc_ctl registers.
>>   * @soc_ctl_map:       Map to get offsets into soc_ctl registers.
>>   * @quirks:            Arasan deviations from spec.
>> + * @uhs_gpio:          Pointer to the uhs gpio.
>>   */
>>  struct sdhci_arasan_data {
>>         struct sdhci_host *host;
>> @@ -150,6 +153,7 @@ struct sdhci_arasan_data {
>>         struct regmap   *soc_ctl_base;
>>         const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
>>         unsigned int    quirks;
>> +       struct gpio_desc *uhs_gpio;
>>
>>  /* Controller does not have CD wired and will not function normally without */
>>  #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST        BIT(0)
>> @@ -361,6 +365,112 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
>>         return -EINVAL;
>>  }
>>
>> +static int sdhci_arasan_keembay_voltage_switch(struct mmc_host *mmc,
>> +                                      struct mmc_ios *ios)
>> +{
>> +       struct sdhci_host *host = mmc_priv(mmc);
>> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> +       struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
>> +       u16 ctrl_2, clk;
>> +       int ret;
>> +
>> +       switch (ios->signal_voltage) {
>> +       case MMC_SIGNAL_VOLTAGE_180:
>> +               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
>> +               clk &= ~SDHCI_CLOCK_CARD_EN;
>> +               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>> +
>> +               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
>> +               if (clk & SDHCI_CLOCK_CARD_EN)
>> +                       return -EAGAIN;
>> +
>> +               sdhci_writeb(host, SDHCI_POWER_ON | SDHCI_POWER_180,
>> +                                  SDHCI_POWER_CONTROL);
>> +
>> +               /*
>> +                * Set VDDIO_B voltage to Low for 1.8V
>> +                * which is controlling by GPIO Expander.
>> +                */
>> +               gpiod_set_value_cansleep(sdhci_arasan->uhs_gpio, 0);
>> +
>> +               /*
>> +                * This is like a final gatekeeper. Need to ensure changed voltage
>> +                * is settled before and after turn on this bit.
>> +                */
>> +               usleep_range(1000, 1100);
>> +
>> +               ret = keembay_sd_voltage_selection(KEEMBAY_SET_1V8_VOLT);
>> +               if (ret)
>> +                       return ret;
>> +
>> +               usleep_range(1000, 1100);
> 
> No, sorry, but I don't like this.
> 
> This looks like a GPIO regulator with an extension of using the
> keembay_sd_voltage_selection() thingy. I think you can model these
> things behind a regulator and hook it up as a vqmmc supply in DT
> instead. BTW, this is the common way we deal with these things for mmc
> host drivers.

It seemed to me that would just result in calling regulator API instead of
GPIO API but the flow above would otherwise be unchanged i.e. no benefit




More information about the linux-arm-kernel mailing list