diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/button/button-qcom-pmic.c | 15 | ||||
-rw-r--r-- | drivers/clk/qcom/clock-apq8016.c | 17 | ||||
-rw-r--r-- | drivers/clk/qcom/clock-qcom.c | 27 | ||||
-rw-r--r-- | drivers/clk/qcom/clock-qcom.h | 26 | ||||
-rw-r--r-- | drivers/i2c/designware_i2c.c | 30 | ||||
-rw-r--r-- | drivers/mmc/am654_sdhci.c | 5 | ||||
-rw-r--r-- | drivers/power/regulator/qcom_usb_vbus_regulator.c | 37 |
7 files changed, 114 insertions, 43 deletions
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c index e3bb9bd758a..85addfe32a2 100644 --- a/drivers/button/button-qcom-pmic.c +++ b/drivers/button/button-qcom-pmic.c @@ -143,6 +143,21 @@ static int qcom_pwrkey_probe(struct udevice *dev) priv->base = base; + ret = dev_read_u32(dev, "linux,code", &priv->code); + if (ret == 0) { + /* convert key, if read OK */ + switch (priv->code) { + case KEY_VOLUMEDOWN: + priv->code = KEY_DOWN; + uc_plat->label = "Volume Down"; + break; + case KEY_VOLUMEUP: + priv->code = KEY_UP; + uc_plat->label = "Volume Up"; + break; + } + } + /* Do a sanity check */ ret = pmic_reg_read(priv->pmic, priv->base + REG_TYPE); if (ret != 0x1 && ret != 0xb) { diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c index 6a53f900a9e..b7bd9c9a342 100644 --- a/drivers/clk/qcom/clock-apq8016.c +++ b/drivers/clk/qcom/clock-apq8016.c @@ -23,10 +23,7 @@ #define APCS_GPLL_ENA_VOTE (0x45000) #define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004) -#define SDCC_BCR(n) ((n * 0x1000) + 0x41000) -#define SDCC_CMD_RCGR(n) (((n + 1) * 0x1000) + 0x41004) -#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018) -#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C) +#define SDCC_CMD_RCGR(n) (((n) * 0x1000) + 0x42004) /* BLSP1 AHB clock (root clock for BLSP) */ #define BLSP1_AHB_CBCR 0x1008 @@ -54,9 +51,13 @@ static struct vote_clk gcc_blsp1_ahb_clk = { }; static const struct gate_clk apq8016_clks[] = { - GATE_CLK(GCC_PRNG_AHB_CLK, 0x45004, BIT(8)), - GATE_CLK(GCC_USB_HS_AHB_CLK, 0x41008, BIT(0)), - GATE_CLK(GCC_USB_HS_SYSTEM_CLK, 0x41004, BIT(0)), + GATE_CLK_POLLED(GCC_PRNG_AHB_CLK, 0x45004, BIT(8), 0x13004), + GATE_CLK_POLLED(GCC_SDCC1_AHB_CLK, 0x4201c, BIT(0), 0x4201c), + GATE_CLK_POLLED(GCC_SDCC1_APPS_CLK, 0x42018, BIT(0), 0x42018), + GATE_CLK_POLLED(GCC_SDCC2_AHB_CLK, 0x4301c, BIT(0), 0x4301c), + GATE_CLK_POLLED(GCC_SDCC2_APPS_CLK, 0x43018, BIT(0), 0x43018), + GATE_CLK_POLLED(GCC_USB_HS_AHB_CLK, 0x41008, BIT(0), 0x41008), + GATE_CLK_POLLED(GCC_USB_HS_SYSTEM_CLK, 0x41004, BIT(0), 0x41004), }; /* SDHCI */ @@ -67,12 +68,10 @@ static int apq8016_clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) if (rate == 200000000) div = 4; - clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot)); /* 800Mhz/div, gpll0 */ clk_rcg_set_rate_mnd(priv->base, SDCC_CMD_RCGR(slot), div, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_enable_gpll0(priv->base, &gpll0_vote_clk); - clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); return rate; } diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c index 7687bbe6a23..6b46d9db744 100644 --- a/drivers/clk/qcom/clock-qcom.c +++ b/drivers/clk/qcom/clock-qcom.c @@ -74,6 +74,33 @@ void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); } +int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) +{ + if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) { + log_err("gcc@%#08llx: unknown clock ID %lu!\n", + priv->base, id); + return -ENOENT; + } + + setbits_le32(priv->base + priv->data->clks[id].reg, priv->data->clks[id].en_val); + if (priv->data->clks[id].cbcr_reg) { + unsigned int count; + u32 val; + + for (count = 0; count < 200; count++) { + val = readl(priv->base + priv->data->clks[id].cbcr_reg); + val &= BRANCH_CHECK_MASK; + if (val == BRANCH_ON_VAL || val == BRANCH_NOC_FSM_ON_VAL) + break; + udelay(1); + } + if (WARN(count == 200, "WARNING: Clock @ %#lx [%#010x] stuck at off\n", + priv->data->clks[id].cbcr_reg, val)) + return -EBUSY; + } + return 0; +} + #define APPS_CMD_RCGR_UPDATE BIT(0) /* Update clock command via CMD_RCGR */ diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index f43edea2525..1b60882dae4 100644 --- a/drivers/clk/qcom/clock-qcom.h +++ b/drivers/clk/qcom/clock-qcom.h @@ -52,13 +52,20 @@ struct freq_tbl { struct gate_clk { uintptr_t reg; u32 en_val; + uintptr_t cbcr_reg; const char *name; }; +/* + * GATE_CLK() is deprecated: Use GATE_CLK_POLLED() instead to ensure the clock + * is running before we start making use of devices or registers. + */ #ifdef DEBUG -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, #clk } +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, #clk } +#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, #clk } #else -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, NULL } +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, NULL } +#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, NULL } #endif struct qcom_reset_map { @@ -107,19 +114,6 @@ void clk_rcg_set_rate(phys_addr_t base, uint32_t cmd_rcgr, int div, int source); void clk_phy_mux_enable(phys_addr_t base, uint32_t cmd_rcgr, bool enabled); -static inline int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) -{ - u32 val; - if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) { - log_err("gcc@%#08llx: unknown clock ID %lu!\n", - priv->base, id); - return -ENOENT; - } - - val = readl(priv->base + priv->data->clks[id].reg); - writel(val | priv->data->clks[id].en_val, priv->base + priv->data->clks[id].reg); - - return 0; -} +int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id); #endif diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index e8c1623d41f..a54976e7889 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -404,7 +404,7 @@ static int i2c_wait_for_bb(struct i2c_regs *i2c_base) /* Evaluate timeout */ if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) - return 1; + return -ETIMEDOUT; } return 0; @@ -413,8 +413,10 @@ static int i2c_wait_for_bb(struct i2c_regs *i2c_base) static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr, int alen) { - if (i2c_wait_for_bb(i2c_base)) - return 1; + int ret = i2c_wait_for_bb(i2c_base); + + if (ret) + return ret; i2c_setaddress(i2c_base, chip); while (alen) { @@ -429,6 +431,7 @@ static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr, static int i2c_xfer_finish(struct i2c_regs *i2c_base) { ulong start_stop_det = get_timer(0); + int ret; while (1) { if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) { @@ -439,9 +442,10 @@ static int i2c_xfer_finish(struct i2c_regs *i2c_base) } } - if (i2c_wait_for_bb(i2c_base)) { + ret = i2c_wait_for_bb(i2c_base); + if (ret) { printf("Timed out waiting for bus\n"); - return 1; + return ret; } i2c_flush_rxfifo(i2c_base); @@ -464,6 +468,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, { unsigned long start_time_rx; unsigned int active = 0; + int ret; #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* @@ -484,8 +489,9 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, addr); #endif - if (i2c_xfer_init(i2c_base, dev, addr, alen)) - return 1; + ret = i2c_xfer_init(i2c_base, dev, addr, alen); + if (ret) + return ret; start_time_rx = get_timer(0); while (len) { @@ -510,7 +516,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, start_time_rx = get_timer(0); active = 0; } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { - return 1; + return -ETIMEDOUT; } } @@ -532,6 +538,7 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, { int nb = len; unsigned long start_time_tx; + int ret; #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* @@ -552,8 +559,9 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, addr); #endif - if (i2c_xfer_init(i2c_base, dev, addr, alen)) - return 1; + ret = i2c_xfer_init(i2c_base, dev, addr, alen); + if (ret) + return ret; start_time_tx = get_timer(0); while (len) { @@ -569,7 +577,7 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { printf("Timed out. i2c write Failed\n"); - return 1; + return -ETIMEDOUT; } } diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 0df3568f073..d3c8f94dd0c 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -527,11 +527,16 @@ static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) void am654_sdhci_set_control_reg(struct sdhci_host *host) { struct mmc *mmc = host->mmc; + u32 reg; + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; sdhci_set_voltage(host); if (mmc->selected_mode > MMC_HS_52) sdhci_set_uhs_timing(host); + else + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } const struct sdhci_ops am654_sdhci_ops = { diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c index 2d58ef5e111..07f118d4797 100644 --- a/drivers/power/regulator/qcom_usb_vbus_regulator.c +++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c @@ -15,14 +15,33 @@ #include <power/pmic.h> #include <power/regulator.h> -#define CMD_OTG 0x50 +enum pm8x50b_vbus { + PM8150B, + PM8550B, +}; + #define OTG_EN BIT(0) -// The 0 bit in this register's bit field is undocumented -#define OTG_CFG 0x56 + #define OTG_EN_SRC_CFG BIT(1) +struct qcom_otg_regs { + u32 otg_cmd; + u32 otg_cfg; +}; struct qcom_usb_vbus_priv { phys_addr_t base; + struct qcom_otg_regs *regs; +}; + +static const struct qcom_otg_regs qcom_otg[] = { + [PM8150B] = { + .otg_cmd = 0x40, + .otg_cfg = 0x53, + }, + [PM8550B] = { + .otg_cmd = 0x50, + .otg_cfg = 0x56, + }, }; static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) @@ -38,8 +57,9 @@ static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_en_reg = priv->base + CMD_OTG; + int otg_en_reg = priv->base + regs->otg_cmd; int ret; ret = pmic_reg_read(dev->parent, otg_en_reg); @@ -53,8 +73,9 @@ static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_en_reg = priv->base + CMD_OTG; + int otg_en_reg = priv->base + regs->otg_cmd; int ret; if (enable) { @@ -76,8 +97,9 @@ static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) static int qcom_usb_vbus_regulator_probe(struct udevice *dev) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_cfg_reg = priv->base + OTG_CFG; + int otg_cfg_reg = priv->base + regs->otg_cfg; int ret; /* Disable HW logic for VBUS enable */ @@ -96,7 +118,8 @@ static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = { }; static const struct udevice_id qcom_usb_vbus_regulator_ids[] = { - { .compatible = "qcom,pm8150b-vbus-reg"}, + { .compatible = "qcom,pm8150b-vbus-reg", .data = PM8150B }, + { .compatible = "qcom,pm8550b-vbus-reg", .data = PM8550B }, { }, }; |