Merge https://source.denx.de/u-boot/custodians/u-boot-snapdragon into next
- Reworks Qualcomm support to be more generic, dropping board specific
build targets and relying on DT as the only source of truth
- Switches all Qualcomm devices to use upstream devicetree
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index c0ce570..e6647f7 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -13,6 +13,7 @@
#include <errno.h>
#include <asm/io.h>
#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-msm8916.h>
#include "clock-qcom.h"
@@ -102,20 +103,20 @@
};
/* UART: 115200 */
-static int clk_init_uart(struct msm_clk_priv *priv)
+int apq8016_clk_init_uart(phys_addr_t base)
{
/* Enable AHB clock */
- clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
+ clk_enable_vote_clk(base, &gcc_blsp1_ahb_clk);
/* 7372800 uart block clock @ GPLL0 */
- clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625,
+ clk_rcg_set_rate_mnd(base, &uart2_regs, 1, 144, 15625,
CFG_CLK_SRC_GPLL0, 16);
/* Vote for gpll0 clock */
- clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+ clk_enable_gpll0(base, &gpll0_vote_clk);
/* Enable core clk */
- clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
+ clk_enable_cbc(base + BLSP1_UART2_APPS_CBCR);
return 0;
}
@@ -125,14 +126,14 @@
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
- case 0: /* SDC1 */
+ case GCC_SDCC1_APPS_CLK: /* SDC1 */
return clk_init_sdc(priv, 0, rate);
break;
- case 1: /* SDC2 */
+ case GCC_SDCC2_APPS_CLK: /* SDC2 */
return clk_init_sdc(priv, 1, rate);
break;
- case 4: /* UART2 */
- return clk_init_uart(priv);
+ case GCC_BLSP1_UART2_APPS_CLK: /* UART2 */
+ return apq8016_clk_init_uart(priv->base);
break;
default:
return 0;
@@ -145,7 +146,7 @@
static const struct udevice_id gcc_apq8016_of_match[] = {
{
- .compatible = "qcom,gcc-apq8016",
+ .compatible = "qcom,gcc-msm8916",
.data = (ulong)&apq8016_clk_data,
},
{ }
diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c
index cf1a347..a473161 100644
--- a/drivers/clk/qcom/clock-apq8096.c
+++ b/drivers/clk/qcom/clock-apq8096.c
@@ -13,6 +13,7 @@
#include <errno.h>
#include <asm/io.h>
#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-msm8996.h>
#include "clock-qcom.h"
@@ -107,10 +108,10 @@
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
- case 0: /* SDC1 */
+ case GCC_SDCC1_APPS_CLK: /* SDC1 */
return clk_init_sdc(priv, rate);
break;
- case 4: /*UART2*/
+ case GCC_BLSP2_UART2_APPS_CLK: /*UART2*/
return clk_init_uart(priv);
default:
return 0;
@@ -123,7 +124,7 @@
static const struct udevice_id gcc_apq8096_of_match[] = {
{
- .compatible = "qcom,gcc-apq8096",
+ .compatible = "qcom,gcc-msm8996",
.data = (ulong)&apq8096_clk_data,
},
{ }
diff --git a/drivers/clk/qcom/clock-qcs404.c b/drivers/clk/qcom/clock-qcs404.c
index f5b3528..958312b 100644
--- a/drivers/clk/qcom/clock-qcs404.c
+++ b/drivers/clk/qcom/clock-qcs404.c
@@ -193,24 +193,18 @@
switch (clk->id) {
case GCC_BLSP1_UART2_APPS_CLK:
- /* UART: 115200 */
+ /* UART: 1843200Hz for a fixed 115200 baudrate (19200000 * (12/125)) */
clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 0, 12, 125,
CFG_CLK_SRC_CXO, 16);
clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
- break;
- case GCC_BLSP1_AHB_CLK:
- clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
- break;
+ return 1843200;
case GCC_SDCC1_APPS_CLK:
/* SDCC1: 200MHz */
clk_rcg_set_rate_mnd(priv->base, &sdc_regs, 7, 0, 0,
CFG_CLK_SRC_GPLL0, 8);
clk_enable_gpll0(priv->base, &gpll0_vote_clk);
clk_enable_cbc(priv->base + SDCC_APPS_CBCR(1));
- break;
- case GCC_SDCC1_AHB_CLK:
- clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1));
- break;
+ return rate;
case GCC_ETH_RGMII_CLK:
if (rate == 250000000)
clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 0, 0,
@@ -224,11 +218,15 @@
else if (rate == 5000000)
clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 1, 50,
CFG_CLK_SRC_GPLL1, 8);
- break;
- default:
- return 0;
+ return rate;
}
+ /* There is a bug only seeming to affect this board where the MMC driver somehow calls
+ * clk_set_rate() on a clock with id 0 which is associated with the qcom_clk device.
+ * The only clock with ID 0 is the xo_board clock which should not be associated with
+ * this device...
+ */
+ log_debug("Unknown clock id %ld\n", clk->id);
return 0;
}
@@ -305,6 +303,9 @@
clk_rcg_set_rate(priv->base, &blsp1_qup4_i2c_apps_regs, 0,
CFG_CLK_SRC_CXO);
break;
+ case GCC_SDCC1_AHB_CLK:
+ clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1));
+ break;
default:
return 0;
}
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index 80cd28b..5e57b0c 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -39,6 +39,10 @@
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(priv->pin_data, gpio))
+ return 0;
+
/* Disable OE bit */
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
GPIO_OE_MASK, GPIO_OE_DISABLE);
@@ -50,6 +54,10 @@
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(priv->pin_data, gpio))
+ return 0;
+
value = !!value;
/* set value */
writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
@@ -62,6 +70,10 @@
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(priv->pin_data, gpio))
+ return 0;
+
value = !!value;
/* set value */
writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
@@ -76,6 +88,10 @@
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(priv->pin_data, gpio))
+ return 0;
+
return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
}
@@ -83,6 +99,10 @@
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(priv->pin_data, gpio))
+ return 0;
+
if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
return GPIOF_OUTPUT;
diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c
index 6167c84..14a8210 100644
--- a/drivers/gpio/qcom_pmic_gpio.c
+++ b/drivers/gpio/qcom_pmic_gpio.c
@@ -7,10 +7,14 @@
#include <common.h>
#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
#include <log.h>
#include <power/pmic.h>
#include <spmi/spmi.h>
#include <asm/io.h>
+#include <stdlib.h>
#include <asm/gpio.h>
#include <linux/bitops.h>
@@ -64,27 +68,34 @@
#define REG_EN_CTL 0x46
#define REG_EN_CTL_ENABLE (1 << 7)
-struct qcom_gpio_bank {
+/**
+ * pmic_gpio_match_data - platform specific configuration
+ *
+ * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them.
+ * This is a workaround for an unknown bug on some platforms where trying to write the
+ * GPIO configuration registers causes the board to hang.
+ */
+enum pmic_gpio_quirks {
+ QCOM_PMIC_QUIRK_READONLY = (1 << 0),
+};
+
+struct qcom_pmic_gpio_data {
uint32_t pid; /* Peripheral ID on SPMI bus */
bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
+ u32 pin_count;
+ struct udevice *pmic; /* Reference to pmic device for read/write */
};
-static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
- bool input, int value)
+/* dev can be the GPIO or pinctrl device */
+static int _qcom_gpio_set_direction(struct udevice *dev, u32 offset, bool input, int value)
{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
- uint32_t reg_ctl_val;
- int ret;
-
- /* Disable the GPIO */
- ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
- REG_EN_CTL_ENABLE, 0);
- if (ret < 0)
- return ret;
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ u32 gpio_base = plat->pid + REG_OFFSET(offset);
+ u32 reg_ctl_val;
+ int ret = 0;
/* Select the mode and output */
- if (priv->lv_mv_type) {
+ if (plat->lv_mv_type) {
if (input)
reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
else
@@ -96,20 +107,43 @@
reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
}
- ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val);
+ ret = pmic_reg_write(plat->pmic, gpio_base + REG_CTL, reg_ctl_val);
if (ret < 0)
return ret;
- if (priv->lv_mv_type && !input) {
- ret = pmic_reg_write(dev->parent,
+ if (plat->lv_mv_type && !input) {
+ ret = pmic_reg_write(plat->pmic,
gpio_base + REG_LV_MV_OUTPUT_CTL,
!!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
if (ret < 0)
return ret;
}
+ return 0;
+}
+
+static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset,
+ bool input, int value)
+{
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
+ ulong quirks = dev_get_driver_data(dev);
+ int ret = 0;
+
+ /* Some PMICs don't like their GPIOs being configured */
+ if (quirks & QCOM_PMIC_QUIRK_READONLY)
+ return 0;
+
+ /* Disable the GPIO */
+ ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
+ REG_EN_CTL_ENABLE, 0);
+ if (ret < 0)
+ return ret;
+
+ _qcom_gpio_set_direction(dev, offset, input, value);
+
/* Set the right pull (no pull) */
- ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
+ ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_PULL_CTL,
REG_DIG_PULL_NO_PU);
if (ret < 0)
return ret;
@@ -117,13 +151,13 @@
/* Configure output pin drivers if needed */
if (!input) {
/* Select the VIN - VIN0, pin is input so it doesn't matter */
- ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
+ ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_VIN_CTL,
REG_DIG_VIN_VIN0);
if (ret < 0)
return ret;
/* Set the right dig out control */
- ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
+ ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_OUT_CTL,
REG_DIG_OUT_CTL_CMOS |
REG_DIG_OUT_CTL_DRIVE_L);
if (ret < 0)
@@ -148,15 +182,15 @@
static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
int reg;
- reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
+ reg = pmic_reg_read(plat->pmic, gpio_base + REG_CTL);
if (reg < 0)
return reg;
- if (priv->lv_mv_type) {
+ if (plat->lv_mv_type) {
switch (reg & REG_CTL_LV_MV_MODE_MASK) {
case REG_CTL_LV_MV_MODE_INPUT:
return GPIOF_INPUT;
@@ -181,11 +215,11 @@
static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
int reg;
- reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
+ reg = pmic_reg_read(plat->pmic, gpio_base + REG_STATUS);
if (reg < 0)
return reg;
@@ -195,11 +229,11 @@
static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
int value)
{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
/* Set the output value of the gpio */
- if (priv->lv_mv_type)
+ if (plat->lv_mv_type)
return pmic_clrsetbits(dev->parent,
gpio_base + REG_LV_MV_OUTPUT_CTL,
REG_LV_MV_OUTPUT_CTL_MASK,
@@ -209,71 +243,104 @@
REG_CTL_OUTPUT_MASK, !!value);
}
+static int qcom_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (args->args_count < 1)
+ return -EINVAL;
+
+ /* GPIOs in DT are 1-based */
+ desc->offset = args->args[0] - 1;
+ if (desc->offset >= uc_priv->gpio_count)
+ return -EINVAL;
+
+ if (args->args_count < 2)
+ return 0;
+
+ desc->flags = gpio_flags_xlate(args->args[1]);
+
+ return 0;
+}
+
static const struct dm_gpio_ops qcom_gpio_ops = {
.direction_input = qcom_gpio_direction_input,
.direction_output = qcom_gpio_direction_output,
.get_value = qcom_gpio_get_value,
.set_value = qcom_gpio_set_value,
.get_function = qcom_gpio_get_function,
+ .xlate = qcom_gpio_xlate,
};
+static int qcom_gpio_bind(struct udevice *dev)
+{
+
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ ulong quirks = dev_get_driver_data(dev);
+ struct udevice *child;
+ struct driver *drv;
+ int ret;
+
+ drv = lists_driver_lookup_name("qcom_pmic_pinctrl");
+ if (!drv) {
+ log_warning("Cannot find driver '%s'\n", "qcom_pmic_pinctrl");
+ return -ENOENT;
+ }
+
+ /* Bind the GPIO driver as a child of the PMIC. */
+ ret = device_bind_with_driver_data(dev, drv,
+ dev->name,
+ quirks, dev_ofnode(dev), &child);
+ if (ret)
+ return log_msg_ret("bind", ret);
+
+ dev_set_plat(child, plat);
+
+ return 0;
+}
+
static int qcom_gpio_probe(struct udevice *dev)
{
- struct qcom_gpio_bank *priv = dev_get_priv(dev);
- int reg;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+ struct ofnode_phandle_args args;
+ int val, ret;
u64 pid;
+ plat->pmic = dev->parent;
+
pid = dev_read_addr(dev);
if (pid == FDT_ADDR_T_NONE)
return log_msg_ret("bad address", -EINVAL);
- priv->pid = pid;
+ plat->pid = pid;
/* Do a sanity check */
- reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
- if (reg != REG_TYPE_VAL)
+ val = pmic_reg_read(plat->pmic, plat->pid + REG_TYPE);
+ if (val != REG_TYPE_VAL)
return log_msg_ret("bad type", -ENXIO);
- reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH &&
- reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV)
+ val = pmic_reg_read(plat->pmic, plat->pid + REG_SUBTYPE);
+ if (val != REG_SUBTYPE_GPIO_4CH && val != REG_SUBTYPE_GPIOC_4CH &&
+ val != REG_SUBTYPE_GPIO_LV && val != REG_SUBTYPE_GPIO_MV)
return log_msg_ret("bad subtype", -ENXIO);
- priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV ||
- reg == REG_SUBTYPE_GPIO_MV;
-
- return 0;
-}
-
-/*
- * Parse basic GPIO count specified via the gpio-ranges property
- * as specified in Linux devicetrees
- * Returns < 0 on error, otherwise gpio count
- */
-static int qcom_gpio_of_parse_ranges(struct udevice *dev)
-{
- int ret;
- struct ofnode_phandle_args args;
+ plat->lv_mv_type = val == REG_SUBTYPE_GPIO_LV ||
+ val == REG_SUBTYPE_GPIO_MV;
+ /*
+ * Parse basic GPIO count specified via the gpio-ranges property
+ * as specified in upstream devicetrees
+ */
ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
NULL, 3, 0, &args);
if (ret)
return log_msg_ret("gpio-ranges", ret);
- return args.args[2];
-}
-
-static int qcom_gpio_of_to_plat(struct udevice *dev)
-{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- int ret;
-
- ret = qcom_gpio_of_parse_ranges(dev);
- if (ret > 0)
- uc_priv->gpio_count = ret;
- else
- return ret;
+ plat->pin_count = args.args[2];
+ uc_priv->gpio_count = plat->pin_count;
uc_priv->bank_name = "pmic";
return 0;
@@ -282,7 +349,7 @@
static const struct udevice_id qcom_gpio_ids[] = {
{ .compatible = "qcom,pm8916-gpio" },
{ .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
- { .compatible = "qcom,pm8998-gpio" },
+ { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
{ .compatible = "qcom,pms405-gpio" },
{ }
};
@@ -291,9 +358,75 @@
.name = "qcom_pmic_gpio",
.id = UCLASS_GPIO,
.of_match = qcom_gpio_ids,
- .of_to_plat = qcom_gpio_of_to_plat,
- .probe = qcom_gpio_probe,
+ .bind = qcom_gpio_bind,
+ .probe = qcom_gpio_probe,
.ops = &qcom_gpio_ops,
- .priv_auto = sizeof(struct qcom_gpio_bank),
+ .plat_auto = sizeof(struct qcom_pmic_gpio_data),
+ .flags = DM_FLAG_ALLOC_PDATA,
+};
+
+static const struct pinconf_param qcom_pmic_pinctrl_conf_params[] = {
+ { "output-high", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+ { "output-low", PIN_CONFIG_OUTPUT, 0 },
};
+static int qcom_pmic_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+
+ return plat->pin_count;
+}
+
+static const char *qcom_pmic_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ static char name[8];
+
+ /* DT indexes from 1 */
+ snprintf(name, sizeof(name), "gpio%u", selector + 1);
+
+ return name;
+}
+
+static int qcom_pmic_pinctrl_pinconf_set(struct udevice *dev, unsigned int selector,
+ unsigned int param, unsigned int arg)
+{
+ /* We only support configuring the pin as an output, either low or high */
+ return _qcom_gpio_set_direction(dev, selector, false,
+ param == PIN_CONFIG_OUTPUT_ENABLE);
+}
+
+static const char *qcom_pmic_pinctrl_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ if (!selector)
+ return "normal";
+ return NULL;
+}
+
+static int qcom_pmic_pinctrl_generic_get_functions_count(struct udevice *dev)
+{
+ return 1;
+}
+
+static int qcom_pmic_pinctrl_generic_pinmux_set_mux(struct udevice *dev, unsigned int selector,
+ unsigned int func_selector)
+{
+ return 0;
+}
+
+struct pinctrl_ops qcom_pmic_pinctrl_ops = {
+ .get_pins_count = qcom_pmic_pinctrl_get_pins_count,
+ .get_pin_name = qcom_pmic_pinctrl_get_pin_name,
+ .set_state = pinctrl_generic_set_state,
+ .pinconf_num_params = ARRAY_SIZE(qcom_pmic_pinctrl_conf_params),
+ .pinconf_params = qcom_pmic_pinctrl_conf_params,
+ .pinconf_set = qcom_pmic_pinctrl_pinconf_set,
+ .get_function_name = qcom_pmic_pinctrl_get_function_name,
+ .get_functions_count = qcom_pmic_pinctrl_generic_get_functions_count,
+ .pinmux_set = qcom_pmic_pinctrl_generic_pinmux_set_mux,
+};
+
+U_BOOT_DRIVER(qcom_pmic_pinctrl) = {
+ .name = "qcom_pmic_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .ops = &qcom_pmic_pinctrl_ops,
+};
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index fe1e754..059cb3d 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -44,6 +44,7 @@
struct msm_sdhc {
struct sdhci_host host;
void *base;
+ struct clk_bulk clks;
};
struct msm_sdhc_variant_info {
@@ -54,35 +55,57 @@
static int msm_sdc_clk_init(struct udevice *dev)
{
- int node = dev_of_offset(dev);
- uint clk_rate = fdtdec_get_uint(gd->fdt_blob, node, "clock-frequency",
- 400000);
- uint clkd[2]; /* clk_id and clk_no */
- int clk_offset;
- struct udevice *clk_dev;
- struct clk clk;
- int ret;
+ struct msm_sdhc *prv = dev_get_priv(dev);
+ ofnode node = dev_ofnode(dev);
+ ulong clk_rate;
+ int ret, i = 0, n_clks;
+ const char *clk_name;
- ret = fdtdec_get_int_array(gd->fdt_blob, node, "clock", clkd, 2);
+ ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate));
if (ret)
- return ret;
-
- clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
- if (clk_offset < 0)
- return clk_offset;
+ clk_rate = 400000;
- ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
- if (ret)
+ ret = clk_get_bulk(dev, &prv->clks);
+ if (ret) {
+ log_warning("Couldn't get mmc clocks: %d\n", ret);
return ret;
+ }
- clk.id = clkd[1];
- ret = clk_request(clk_dev, &clk);
- if (ret < 0)
+ ret = clk_enable_bulk(&prv->clks);
+ if (ret) {
+ log_warning("Couldn't enable mmc clocks: %d\n", ret);
return ret;
+ }
- ret = clk_set_rate(&clk, clk_rate);
- if (ret < 0)
- return ret;
+ /* If clock-names is unspecified, then the first clock is the core clock */
+ if (!ofnode_get_property(node, "clock-names", &n_clks)) {
+ if (!clk_set_rate(&prv->clks.clks[0], clk_rate)) {
+ log_warning("Couldn't set core clock rate: %d\n", ret);
+ return -EINVAL;
+ }
+ }
+
+ /* Find the index of the "core" clock */
+ while (i < n_clks) {
+ ofnode_read_string_index(node, "clock-names", i, &clk_name);
+ if (!strcmp(clk_name, "core"))
+ break;
+ i++;
+ }
+
+ if (i >= prv->clks.count) {
+ log_warning("Couldn't find core clock (index %d but only have %d clocks)\n", i,
+ prv->clks.count);
+ return -EINVAL;
+ }
+
+ /* The clock is already enabled by the clk_bulk above */
+ clk_rate = clk_set_rate(&prv->clks.clks[i], clk_rate);
+ /* If we get a rate of 0 then something has probably gone wrong. */
+ if (clk_rate == 0 || IS_ERR((void *)clk_rate)) {
+ log_warning("Couldn't set MMC core clock rate: %dE\n", clk_rate ? (int)PTR_ERR((void *)clk_rate) : 0);
+ return -EINVAL;
+ }
return 0;
}
@@ -187,6 +210,8 @@
if (!var_info->mci_removed)
writel(0, priv->base + SDCC_MCI_HC_MODE);
+ clk_release_bulk(&priv->clks);
+
return 0;
}
diff --git a/drivers/phy/qcom/msm8916-usbh-phy.c b/drivers/phy/qcom/msm8916-usbh-phy.c
index 7c9d030..f52046f 100644
--- a/drivers/phy/qcom/msm8916-usbh-phy.c
+++ b/drivers/phy/qcom/msm8916-usbh-phy.c
@@ -74,7 +74,7 @@
{
struct msm_phy_priv *priv = dev_get_priv(dev);
- priv->regs = dev_remap_addr(dev);
+ priv->regs = dev_remap_addr(dev_get_parent(dev));
if (!priv->regs)
return -EINVAL;
@@ -96,7 +96,7 @@
};
static const struct udevice_id msm_phy_ids[] = {
- { .compatible = "qcom,apq8016-usbphy" },
+ { .compatible = "qcom,usb-hs-phy-msm8916" },
{ }
};
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
index 8149ffd..db0e212 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8016.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -14,22 +14,22 @@
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
- "SDC1_CLK",
- "SDC1_CMD",
- "SDC1_DATA",
- "SDC2_CLK",
- "SDC2_CMD",
- "SDC2_DATA",
- "QDSD_CLK",
- "QDSD_CMD",
- "QDSD_DATA0",
- "QDSD_DATA1",
- "QDSD_DATA2",
- "QDSD_DATA3",
+ "sdc1_clk",
+ "sdc1_cmd",
+ "sdc1_data",
+ "sdc2_clk",
+ "sdc2_cmd",
+ "sdc2_data",
+ "qdsd_clk",
+ "qdsd_cmd",
+ "qdsd_data0",
+ "qdsd_data1",
+ "qdsd_data2",
+ "qdsd_data3",
};
static const struct pinctrl_function msm_pinctrl_functions[] = {
- {"blsp1_uart", 2},
+ {"blsp_uart2", 2},
};
static const char *apq8016_get_function_name(struct udevice *dev,
@@ -42,7 +42,7 @@
unsigned int selector)
{
if (selector < 122) {
- snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
return pin_name;
} else {
return msm_pinctrl_pins[selector - 122];
@@ -55,7 +55,10 @@
}
static const struct msm_pinctrl_data apq8016_data = {
- .pin_data = { .pin_count = 133, },
+ .pin_data = {
+ .pin_count = 133,
+ .special_pins_start = 122,
+ },
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = apq8016_get_function_name,
.get_function_mux = apq8016_get_function_mux,
@@ -73,4 +76,5 @@
.of_match = msm_pinctrl_ids,
.ops = &msm_pinctrl_ops,
.bind = msm_pinctrl_bind,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
index d64ab1f..880df8f 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8096.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -14,13 +14,13 @@
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
- "SDC1_CLK",
- "SDC1_CMD",
- "SDC1_DATA",
- "SDC2_CLK",
- "SDC2_CMD",
- "SDC2_DATA",
- "SDC1_RCLK",
+ "sdc1_clk",
+ "sdc1_cmd",
+ "sdc1_data",
+ "sdc2_clk",
+ "sdc2_cmd",
+ "sdc2_data",
+ "sdc1_rclk",
};
static const struct pinctrl_function msm_pinctrl_functions[] = {
@@ -37,7 +37,7 @@
unsigned int selector)
{
if (selector < 150) {
- snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
return pin_name;
} else {
return msm_pinctrl_pins[selector - 150];
@@ -50,7 +50,10 @@
}
static const struct msm_pinctrl_data apq8096_data = {
- .pin_data = { .pin_count = 157, },
+ .pin_data = {
+ .pin_count = 157,
+ .special_pins_start = 150,
+ },
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = apq8096_get_function_name,
.get_function_mux = apq8096_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index 2d99f99..74c04ab 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -46,7 +46,10 @@
}
static const struct msm_pinctrl_data ipq4019_data = {
- .pin_data = { .pin_count = 100, },
+ .pin_data = {
+ .pin_count = 100,
+ .special_pins_start = 100, /* There are no special pins */
+ },
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = ipq4019_get_function_name,
.get_function_mux = ipq4019_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index dc3d8c4..ee0624d 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -16,6 +16,7 @@
#include <asm/gpio.h>
#include <dm/pinctrl.h>
#include <linux/bitops.h>
+#include <linux/bug.h>
#include <mach/gpio.h>
#include "pinctrl-qcom.h"
@@ -83,6 +84,10 @@
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ /* Always NOP for special pins, assume they're in the correct state */
+ if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
+ return 0;
+
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
priv->data->get_function_mux(func_selector) << 2);
@@ -94,6 +99,10 @@
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ /* Always NOP for special pins */
+ if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
+ return 0;
+
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
argument = (argument / 2) - 1;
@@ -136,6 +145,9 @@
const char *name;
int ret;
+ if (!data->pin_data.special_pins_start)
+ dev_warn(dev, "Special pins start index not defined!\n");
+
drv = lists_driver_lookup_name("pinctrl_qcom");
if (!drv)
return -ENOENT;
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
index ac00afa..3a2d468 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -10,20 +10,24 @@
#include "pinctrl-qcom.h"
+#define NORTH 0x00300000
+#define SOUTH 0x00000000
+#define EAST 0x06b00000
+
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
- "SDC1_RCLK",
- "SDC1_CLK",
- "SDC1_CMD",
- "SDC1_DATA",
- "SDC2_CLK",
- "SDC2_CMD",
- "SDC2_DATA",
+ "sdc1_rclk",
+ "sdc1_clk",
+ "sdc1_cmd",
+ "sdc1_data",
+ "sdc2_clk",
+ "sdc2_cmd",
+ "sdc2_data",
};
static const struct pinctrl_function msm_pinctrl_functions[] = {
- {"blsp_uart2", 1},
+ {"gpio", 0},
{"rgmii_int", 1},
{"rgmii_ck", 1},
{"rgmii_tx", 1},
@@ -37,6 +41,40 @@
{"blsp_i2c_scl_a2", 3},
{"blsp_i2c3", 2},
{"blsp_i2c4", 1},
+ {"blsp_uart_tx_a2", 1},
+ {"blsp_uart_rx_a2", 1},
+};
+
+static const unsigned int qcs404_pin_offsets[] = {
+ [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, [4] = SOUTH,
+ [5] = SOUTH, [6] = SOUTH, [7] = SOUTH, [8] = SOUTH, [9] = SOUTH,
+ [10] = SOUTH, [11] = SOUTH, [12] = SOUTH, [13] = SOUTH, [14] = SOUTH,
+ [15] = SOUTH, [16] = SOUTH, [17] = NORTH, [18] = NORTH, [19] = NORTH,
+ [20] = NORTH, [21] = SOUTH, [22] = NORTH, [23] = NORTH, [24] = NORTH,
+ [25] = NORTH, [26] = EAST, [27] = EAST, [28] = EAST, [29] = EAST,
+ [30] = NORTH, [31] = NORTH, [32] = NORTH, [33] = NORTH, [34] = SOUTH,
+ [35] = SOUTH, [36] = NORTH, [37] = NORTH, [38] = NORTH, [39] = EAST,
+ [40] = EAST, [41] = EAST, [42] = EAST, [43] = EAST, [44] = EAST,
+ [45] = EAST, [46] = EAST, [47] = EAST, [48] = EAST, [49] = EAST,
+ [50] = EAST, [51] = EAST, [52] = EAST, [53] = EAST, [54] = EAST,
+ [55] = EAST, [56] = EAST, [57] = EAST, [58] = EAST, [59] = EAST,
+ [60] = NORTH, [61] = NORTH, [62] = NORTH, [63] = NORTH, [64] = NORTH,
+ [65] = NORTH, [66] = NORTH, [67] = NORTH, [68] = NORTH, [69] = NORTH,
+ [70] = NORTH, [71] = NORTH, [72] = NORTH, [73] = NORTH, [74] = NORTH,
+ [75] = NORTH, [76] = NORTH, [77] = NORTH, [78] = EAST, [79] = EAST,
+ [80] = EAST, [81] = EAST, [82] = NORTH, [83] = NORTH, [84] = NORTH,
+ [85] = NORTH, [86] = EAST, [87] = EAST, [88] = EAST, [89] = EAST,
+ [90] = EAST, [91] = EAST, [92] = EAST, [93] = EAST, [94] = EAST,
+ [95] = EAST, [96] = EAST, [97] = EAST, [98] = EAST, [99] = EAST,
+ [100] = EAST, [101] = EAST, [102] = EAST, [103] = EAST, [104] = EAST,
+ [105] = EAST, [106] = EAST, [107] = EAST, [108] = EAST, [109] = EAST,
+ [110] = EAST, [111] = EAST, [112] = EAST, [113] = EAST, [114] = EAST,
+ [115] = EAST, [116] = EAST, [117] = NORTH, [118] = NORTH, [119] = EAST,
+ /*
+ * There's 126 pins but the last ones are special and have non-standard registers
+ * so we leave them out here. The pinctrl and GPIO drivers both currently ignore
+ * these pins.
+ */
};
static const char *qcs404_get_function_name(struct udevice *dev,
@@ -49,7 +87,7 @@
unsigned int selector)
{
if (selector < 120) {
- snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
return pin_name;
} else {
return msm_pinctrl_pins[selector - 120];
@@ -61,8 +99,12 @@
return msm_pinctrl_functions[selector].val;
}
-static struct msm_pinctrl_data qcs404_data = {
- .pin_data = { .pin_count = 126, },
+static const struct msm_pinctrl_data qcs404_data = {
+ .pin_data = {
+ .pin_count = 126,
+ .pin_offsets = qcs404_pin_offsets,
+ .special_pins_start = 120,
+ },
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = qcs404_get_function_name,
.get_function_mux = qcs404_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 9f0f408..76bd8c4 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -75,10 +75,11 @@
return msm_pinctrl_functions[selector].val;
}
-static struct msm_pinctrl_data sdm845_data = {
+static const struct msm_pinctrl_data sdm845_data = {
.pin_data = {
.pin_offsets = sdm845_pin_offsets,
- .pin_count = ARRAY_SIZE(sdm845_pin_offsets),
+ .pin_count = 154,
+ .special_pins_start = 150,
},
.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
.get_function_name = sdm845_get_function_name,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 26460c4..fbd351a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -319,6 +319,14 @@
will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running.
+config DEBUG_UART_MSM
+ bool "Qualcomm QUP UART debug"
+ depends on ARCH_SNAPDRAGON
+ help
+ Select this to enable a debug UART using the serial_msm driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver-model serial is running.
+
config DEBUG_UART_MSM_GENI
bool "Qualcomm snapdragon"
depends on ARCH_SNAPDRAGON
diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c
index f4d9631..ac4280c 100644
--- a/drivers/serial/serial_msm.c
+++ b/drivers/serial/serial_msm.c
@@ -160,29 +160,14 @@
{
uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
"clock-frequency", 115200);
- uint clkd[2]; /* clk_id and clk_no */
- int clk_offset;
- struct udevice *clk_dev;
struct clk clk;
int ret;
- ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "clock",
- clkd, 2);
- if (ret)
- return ret;
-
- clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
- if (clk_offset < 0)
- return clk_offset;
-
- ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
- if (ret)
- return ret;
-
- clk.id = clkd[1];
- ret = clk_request(clk_dev, &clk);
- if (ret < 0)
+ ret = clk_get_by_name(dev, "core", &clk);
+ if (ret < 0) {
+ pr_warn("%s: Failed to get clock: %d\n", __func__, ret);
return ret;
+ }
ret = clk_set_rate(&clk, clk_rate);
if (ret < 0)
@@ -218,7 +203,6 @@
if (ret)
return ret;
- pinctrl_select_state(dev, "uart");
uart_dm_init(priv);
return 0;
@@ -251,4 +235,42 @@
.priv_auto = sizeof(struct msm_serial_data),
.probe = msm_serial_probe,
.ops = &msm_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_MSM
+
+static struct msm_serial_data init_serial_data = {
+ .base = CONFIG_VAL(DEBUG_UART_BASE),
+ .clk_rate = 7372800,
};
+
+#include <debug_uart.h>
+
+/* Uncomment to turn on UART clocks when debugging U-Boot as aboot on MSM8916 */
+//int apq8016_clk_init_uart(phys_addr_t gcc_base);
+
+static inline void _debug_uart_init(void)
+{
+ /* Uncomment to turn on UART clocks when debugging U-Boot as aboot on MSM8916 */
+ //apq8016_clk_init_uart(0x1800000);
+ uart_dm_init(&init_serial_data);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct msm_serial_data *priv = &init_serial_data;
+
+ while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
+ !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
+ ;
+
+ writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
+
+ writel(1, priv->base + UARTDM_NCF_TX);
+ writel(ch, priv->base + UARTDM_TF);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 6fb2de8..a379a00 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -21,6 +21,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <malloc.h>
+#include <power/regulator.h>
#include <usb.h>
#include "core.h"
#include "gadget.h"
@@ -47,6 +48,7 @@
struct dwc3_generic_host_priv {
struct xhci_ctrl xhci_ctrl;
struct dwc3_generic_priv gen_priv;
+ struct udevice *vbus_supply;
};
static int dwc3_generic_probe(struct udevice *dev,
@@ -240,11 +242,24 @@
if (rc)
return rc;
+ rc = device_get_supply_regulator(dev, "vbus-supply", &priv->vbus_supply);
+ if (rc)
+ debug("%s: No vbus regulator found: %d\n", dev->name, rc);
+
+ /* Only returns an error if regulator is valid and failed to enable due to a driver issue */
+ rc = regulator_set_enable_if_allowed(priv->vbus_supply, true);
+ if (rc)
+ return rc;
+
hccr = (struct xhci_hccr *)priv->gen_priv.base;
hcor = (struct xhci_hcor *)(priv->gen_priv.base +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
- return xhci_register(dev, hccr, hcor);
+ rc = xhci_register(dev, hccr, hcor);
+ if (rc)
+ regulator_set_enable_if_allowed(priv->vbus_supply, false);
+
+ return rc;
}
static int dwc3_generic_host_remove(struct udevice *dev)
@@ -252,9 +267,12 @@
struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
int rc;
- rc = xhci_deregister(dev);
+ /* This function always returns 0 */
+ xhci_deregister(dev);
+
+ rc = regulator_set_enable_if_allowed(priv->vbus_supply, false);
if (rc)
- return rc;
+ debug("%s: Failed to disable vbus regulator: %d\n", dev->name, rc);
return dwc3_generic_remove(dev, &priv->gen_priv);
}
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index dd0d153..98fe7bc 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <dm.h>
+#include <dm/lists.h>
#include <errno.h>
#include <usb.h>
#include <usb/ehci-ci.h>
@@ -119,6 +120,24 @@
return 0;
}
+static int ehci_usb_of_bind(struct udevice *dev)
+{
+ ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
+ ofnode phy_node;
+
+ if (!ofnode_valid(ulpi_node))
+ return 0;
+
+ phy_node = ofnode_first_subnode(ulpi_node);
+ if (!ofnode_valid(phy_node)) {
+ printf("%s: ulpi subnode with no phy\n", __func__);
+ return -ENOENT;
+ }
+
+ return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
+ phy_node, NULL);
+}
+
#if defined(CONFIG_CI_UDC)
/* Little quirk that MSM needs with Chipidea controller
* Must reinit phy after reset
@@ -132,7 +151,7 @@
#endif
static const struct udevice_id ehci_usb_ids[] = {
- { .compatible = "qcom,ehci-host", },
+ { .compatible = "qcom,ci-hdrc", },
{ }
};
@@ -141,6 +160,7 @@
.id = UCLASS_USB,
.of_match = ehci_usb_ids,
.of_to_plat = ehci_usb_of_to_plat,
+ .bind = ehci_usb_of_bind,
.probe = ehci_usb_probe,
.remove = ehci_usb_remove,
.ops = &ehci_usb_ops,