CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_MSM_GPIO=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_MMC_SDHCI=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
CONFIG_DM_PMIC=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
CONFIG_USB=y
CONFIG_ENV_EXT4_DEVICE_AND_PART="0:1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_CLK=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
CONFIG_DM_PMIC=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
# CONFIG_NET is not set
CONFIG_CLK=y
CONFIG_MSM_GPIO=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_PINCTRL=y
CONFIG_DM_PMIC=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_MSM_GENI_SERIAL=y
CONFIG_SPMI_MSM=y
CONFIG_LMB_MAX_REGIONS=64
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_PMIC_ACT8846=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_RK8XX=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_DM_HWSPINLOCK=y
CONFIG_HWSPINLOCK_SANDBOX=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_PMIC_MC34708=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_RK8XX=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
CONFIG_DFU_SF=y
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_PMIC_MC34708=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
CONFIG_PMIC_S5M8767=y
CONFIG_DM_DEMO_SHAPE=y
CONFIG_SPL_FIRMWARE=y
CONFIG_GPIO_HOG=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_PMIC_MC34708=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_RK8XX=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
CONFIG_DM_DEMO_SHAPE=y
CONFIG_SPL_FIRMWARE=y
CONFIG_GPIO_HOG=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_PMIC_MC34708=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_RK8XX=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
CONFIG_DM_DEMO_SHAPE=y
CONFIG_SPL_FIRMWARE=y
CONFIG_GPIO_HOG=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_PMIC_MC34708=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
CONFIG_PMIC_RK8XX=y
CONFIG_PMIC_S2MPS11=y
CONFIG_DM_PMIC_SANDBOX=y
# CONFIG_DM_STDIO is not set
CONFIG_CLK=y
CONFIG_MSM_GPIO=y
-CONFIG_PM8916_GPIO=y
+CONFIG_QCOM_PMIC_GPIO=y
CONFIG_PINCTRL=y
CONFIG_DM_PMIC=y
-CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_QCOM=y
# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
CONFIG_SPMI_MSM=y
CONFIG_DM_VIDEO=y
+++ /dev/null
-Qualcomm pm8916 PMIC
-
-This PMIC is connected using SPMI bus so should be child of SPMI bus controller.
-
-Required properties:
-- compatible: "qcom,spmi-pmic";
-- reg: SPMI Slave ID, size (ignored)
-- #address-cells: 0x1 (peripheral ID)
-- #size-cells: 0x1 (size of peripheral register space)
-
-Example:
-
-pm8916@0 {
- compatible = "qcom,spmi-pmic";
- reg = <0x0 0x1>;
- #address-cells = <0x1>;
- #size-cells = <0x1>;
-};
--- /dev/null
+ Qualcomm SPMI PMICs multi-function device bindings
+
+The Qualcomm SPMI series presently includes PM8941, PM8841 and PMA8084
+PMICs. These PMICs use a QPNP scheme through SPMI interface.
+QPNP is effectively a partitioning scheme for dividing the SPMI extended
+register space up into logical pieces, and set of fixed register
+locations/definitions within these regions, with some of these regions
+specifically used for interrupt handling.
+
+The QPNP PMICs are used with the Qualcomm Snapdragon series SoCs, and are
+interfaced to the chip via the SPMI (System Power Management Interface) bus.
+Support for multiple independent functions are implemented by splitting the
+16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes
+each. A function can consume one or more of these fixed-size register regions.
+
+Required properties:
+- compatible: Should contain one of:
+ "qcom,pm660",
+ "qcom,pm660l",
+ "qcom,pm7325",
+ "qcom,pm8004",
+ "qcom,pm8005",
+ "qcom,pm8019",
+ "qcom,pm8028",
+ "qcom,pm8110",
+ "qcom,pm8150",
+ "qcom,pm8150b",
+ "qcom,pm8150c",
+ "qcom,pm8150l",
+ "qcom,pm8226",
+ "qcom,pm8350c",
+ "qcom,pm8841",
+ "qcom,pm8901",
+ "qcom,pm8909",
+ "qcom,pm8916",
+ "qcom,pm8941",
+ "qcom,pm8950",
+ "qcom,pm8953",
+ "qcom,pm8994",
+ "qcom,pm8998",
+ "qcom,pma8084",
+ "qcom,pmd9635",
+ "qcom,pmi8950",
+ "qcom,pmi8962",
+ "qcom,pmi8994",
+ "qcom,pmi8998",
+ "qcom,pmk8002",
+ "qcom,pmk8350",
+ "qcom,pmr735a",
+ "qcom,smb2351",
+ or generalized "qcom,spmi-pmic".
+- reg: Specifies the SPMI USID slave address for this device.
+ For more information see:
+ Documentation/devicetree/bindings/spmi/spmi.yaml
+
+Required properties for peripheral child nodes:
+- compatible: Should contain "qcom,xxx", where "xxx" is a peripheral name.
+
+Optional properties for peripheral child nodes:
+- interrupts: Interrupts are specified as a 4-tuple. For more information
+ see:
+ Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml
+- interrupt-names: Corresponding interrupt name to the interrupts property
+
+Each child node of SPMI slave id represents a function of the PMIC. In the
+example below the rtc device node represents a peripheral of pm8941
+SID = 0. The regulator device node represents a peripheral of pm8941 SID = 1.
+
+Example:
+
+ spmi {
+ compatible = "qcom,spmi-pmic-arb";
+
+ pm8941@0 {
+ compatible = "qcom,pm8941", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+
+ rtc {
+ compatible = "qcom,rtc";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "alarm";
+ };
+ };
+
+ pm8941@1 {
+ compatible = "qcom,pm8941", "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+
+ regulator {
+ compatible = "qcom,regulator";
+ regulator-name = "8941_boost";
+ };
+ };
+ };
legacy GPIO interface. Several subcommands are provided which mirror
the standard 'gpio' command. It should use that instead.
-config PM8916_GPIO
- bool "Qualcomm PM8916 PMIC GPIO/keypad driver"
- depends on DM_GPIO && PMIC_PM8916
+config QCOM_PMIC_GPIO
+ bool "Qualcomm generic PMIC GPIO/keypad driver"
+ depends on DM_GPIO && PMIC_QCOM
help
Support for GPIO pins and power/reset buttons found on
- Qualcomm PM8916 PMIC.
+ Qualcomm SoCs PMIC.
Default name for GPIO bank is "pm8916".
- Power and reset buttons are placed in "pm8916_key" bank and
+ Power and reset buttons are placed in "pwkey_qcom" bank and
have gpio numbers 0 and 1 respectively.
config PCF8575_GPIO
obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o
obj-$(CONFIG_MSM_GPIO) += msm_gpio.o
obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o
-obj-$(CONFIG_$(SPL_TPL_)PM8916_GPIO) += pm8916_gpio.o
+obj-$(CONFIG_$(SPL_TPL_)QCOM_PMIC_GPIO) += qcom_pmic_gpio.o
obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o
obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
- *
- */
-
-#include <common.h>
-#include <dm.h>
-#include <log.h>
-#include <power/pmic.h>
-#include <spmi/spmi.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <linux/bitops.h>
-
-/* Register offset for each gpio */
-#define REG_OFFSET(x) ((x) * 0x100)
-
-/* Register maps */
-
-/* Type and subtype are shared for all pm8916 peripherals */
-#define REG_TYPE 0x4
-#define REG_SUBTYPE 0x5
-
-#define REG_STATUS 0x08
-#define REG_STATUS_VAL_MASK 0x1
-
-/* MODE_CTL */
-#define REG_CTL 0x40
-#define REG_CTL_MODE_MASK 0x70
-#define REG_CTL_MODE_INPUT 0x00
-#define REG_CTL_MODE_INOUT 0x20
-#define REG_CTL_MODE_OUTPUT 0x10
-#define REG_CTL_OUTPUT_MASK 0x0F
-
-#define REG_DIG_VIN_CTL 0x41
-#define REG_DIG_VIN_VIN0 0
-
-#define REG_DIG_PULL_CTL 0x42
-#define REG_DIG_PULL_NO_PU 0x5
-
-#define REG_DIG_OUT_CTL 0x45
-#define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
-#define REG_DIG_OUT_CTL_DRIVE_L 0x1
-
-#define REG_EN_CTL 0x46
-#define REG_EN_CTL_ENABLE (1 << 7)
-
-struct pm8916_gpio_bank {
- uint32_t pid; /* Peripheral ID on SPMI bus */
-};
-
-static int pm8916_gpio_set_direction(struct udevice *dev, unsigned offset,
- bool input, int value)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
- 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;
-
- /* Select the mode */
- if (input)
- ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
- REG_CTL_MODE_INPUT);
- else
- ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
- REG_CTL_MODE_INOUT | (value ? 1 : 0));
- if (ret < 0)
- return ret;
-
- /* Set the right pull (no pull) */
- ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
- REG_DIG_PULL_NO_PU);
- if (ret < 0)
- return ret;
-
- /* 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,
- 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,
- REG_DIG_OUT_CTL_CMOS |
- REG_DIG_OUT_CTL_DRIVE_L);
- if (ret < 0)
- return ret;
- }
-
- /* Enable the GPIO */
- return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
- REG_EN_CTL_ENABLE);
-}
-
-static int pm8916_gpio_direction_input(struct udevice *dev, unsigned offset)
-{
- return pm8916_gpio_set_direction(dev, offset, true, 0);
-}
-
-static int pm8916_gpio_direction_output(struct udevice *dev, unsigned offset,
- int value)
-{
- return pm8916_gpio_set_direction(dev, offset, false, value);
-}
-
-static int pm8916_gpio_get_function(struct udevice *dev, unsigned offset)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
- int reg;
-
- /* Set the output value of the gpio */
- reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
- if (reg < 0)
- return reg;
-
- switch (reg & REG_CTL_MODE_MASK) {
- case REG_CTL_MODE_INPUT:
- return GPIOF_INPUT;
- case REG_CTL_MODE_INOUT: /* Fallthrough */
- case REG_CTL_MODE_OUTPUT:
- return GPIOF_OUTPUT;
- default:
- return GPIOF_UNKNOWN;
- }
-}
-
-static int pm8916_gpio_get_value(struct udevice *dev, unsigned offset)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
- int reg;
-
- reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
- if (reg < 0)
- return reg;
-
- return !!(reg & REG_STATUS_VAL_MASK);
-}
-
-static int pm8916_gpio_set_value(struct udevice *dev, unsigned offset,
- int value)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
-
- /* Set the output value of the gpio */
- return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
- REG_CTL_OUTPUT_MASK, !!value);
-}
-
-static const struct dm_gpio_ops pm8916_gpio_ops = {
- .direction_input = pm8916_gpio_direction_input,
- .direction_output = pm8916_gpio_direction_output,
- .get_value = pm8916_gpio_get_value,
- .set_value = pm8916_gpio_set_value,
- .get_function = pm8916_gpio_get_function,
-};
-
-static int pm8916_gpio_probe(struct udevice *dev)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- int reg;
-
- priv->pid = dev_read_addr(dev);
- if (priv->pid == FDT_ADDR_T_NONE)
- return log_msg_ret("bad address", -EINVAL);
-
- /* Do a sanity check */
- reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
- if (reg != 0x10)
- return log_msg_ret("bad type", -ENXIO);
-
- reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if (reg != 0x5 && reg != 0x1)
- return log_msg_ret("bad subtype", -ENXIO);
-
- return 0;
-}
-
-static int pm8916_gpio_of_to_plat(struct udevice *dev)
-{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
- uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
- uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
- if (uc_priv->bank_name == NULL)
- uc_priv->bank_name = "pm8916";
-
- return 0;
-}
-
-static const struct udevice_id pm8916_gpio_ids[] = {
- { .compatible = "qcom,pm8916-gpio" },
- { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
- { .compatible = "qcom,pm8998-gpio" },
- { }
-};
-
-U_BOOT_DRIVER(gpio_pm8916) = {
- .name = "gpio_pm8916",
- .id = UCLASS_GPIO,
- .of_match = pm8916_gpio_ids,
- .of_to_plat = pm8916_gpio_of_to_plat,
- .probe = pm8916_gpio_probe,
- .ops = &pm8916_gpio_ops,
- .priv_auto = sizeof(struct pm8916_gpio_bank),
-};
-
-
-/* Add pmic buttons as GPIO as well - there is no generic way for now */
-#define PON_INT_RT_STS 0x10
-#define KPDPWR_ON_INT_BIT 0
-#define RESIN_ON_INT_BIT 1
-
-static int pm8941_pwrkey_get_function(struct udevice *dev, unsigned offset)
-{
- return GPIOF_INPUT;
-}
-
-static int pm8941_pwrkey_get_value(struct udevice *dev, unsigned offset)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
-
- int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
-
- if (reg < 0)
- return 0;
-
- switch (offset) {
- case 0: /* Power button */
- return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
- break;
- case 1: /* Reset button */
- default:
- return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
- break;
- }
-}
-
-static const struct dm_gpio_ops pm8941_pwrkey_ops = {
- .get_value = pm8941_pwrkey_get_value,
- .get_function = pm8941_pwrkey_get_function,
-};
-
-static int pm8941_pwrkey_probe(struct udevice *dev)
-{
- struct pm8916_gpio_bank *priv = dev_get_priv(dev);
- int reg;
-
- priv->pid = dev_read_addr(dev);
- if (priv->pid == FDT_ADDR_T_NONE)
- return log_msg_ret("bad address", -EINVAL);
-
- /* Do a sanity check */
- reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
- if (reg != 0x1)
- return log_msg_ret("bad type", -ENXIO);
-
- reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if ((reg & 0x5) == 0)
- return log_msg_ret("bad subtype", -ENXIO);
-
- return 0;
-}
-
-static int pm8941_pwrkey_of_to_plat(struct udevice *dev)
-{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
- uc_priv->gpio_count = 2;
- uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
- if (uc_priv->bank_name == NULL)
- uc_priv->bank_name = "pm8916_key";
-
- return 0;
-}
-
-static const struct udevice_id pm8941_pwrkey_ids[] = {
- { .compatible = "qcom,pm8916-pwrkey" },
- { .compatible = "qcom,pm8994-pwrkey" },
- { .compatible = "qcom,pm8998-pwrkey" },
- { }
-};
-
-U_BOOT_DRIVER(pwrkey_pm89xx) = {
- .name = "pwrkey_pm89xx",
- .id = UCLASS_GPIO,
- .of_match = pm8941_pwrkey_ids,
- .of_to_plat = pm8941_pwrkey_of_to_plat,
- .probe = pm8941_pwrkey_probe,
- .ops = &pm8941_pwrkey_ops,
- .priv_auto = sizeof(struct pm8916_gpio_bank),
-};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm generic pmic gpio driver
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+
+/* Register offset for each gpio */
+#define REG_OFFSET(x) ((x) * 0x100)
+
+/* Register maps */
+
+/* Type and subtype are shared for all PMIC peripherals */
+#define REG_TYPE 0x4
+#define REG_SUBTYPE 0x5
+
+#define REG_STATUS 0x08
+#define REG_STATUS_VAL_MASK 0x1
+
+/* MODE_CTL */
+#define REG_CTL 0x40
+#define REG_CTL_MODE_MASK 0x70
+#define REG_CTL_MODE_INPUT 0x00
+#define REG_CTL_MODE_INOUT 0x20
+#define REG_CTL_MODE_OUTPUT 0x10
+#define REG_CTL_OUTPUT_MASK 0x0F
+
+#define REG_DIG_VIN_CTL 0x41
+#define REG_DIG_VIN_VIN0 0
+
+#define REG_DIG_PULL_CTL 0x42
+#define REG_DIG_PULL_NO_PU 0x5
+
+#define REG_DIG_OUT_CTL 0x45
+#define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
+#define REG_DIG_OUT_CTL_DRIVE_L 0x1
+
+#define REG_EN_CTL 0x46
+#define REG_EN_CTL_ENABLE (1 << 7)
+
+struct qcom_gpio_bank {
+ uint32_t pid; /* Peripheral ID on SPMI bus */
+};
+
+static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
+ bool input, int value)
+{
+ struct qcom_gpio_bank *priv = dev_get_priv(dev);
+ uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ 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;
+
+ /* Select the mode */
+ if (input)
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_MODE_INPUT);
+ else
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_MODE_INOUT | (value ? 1 : 0));
+ if (ret < 0)
+ return ret;
+
+ /* Set the right pull (no pull) */
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
+ REG_DIG_PULL_NO_PU);
+ if (ret < 0)
+ return ret;
+
+ /* 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,
+ 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,
+ REG_DIG_OUT_CTL_CMOS |
+ REG_DIG_OUT_CTL_DRIVE_L);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable the GPIO */
+ return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
+ REG_EN_CTL_ENABLE);
+}
+
+static int qcom_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ return qcom_gpio_set_direction(dev, offset, true, 0);
+}
+
+static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ return qcom_gpio_set_direction(dev, offset, false, value);
+}
+
+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);
+ int reg;
+
+ /* Set the output value of the gpio */
+ reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
+ if (reg < 0)
+ return reg;
+
+ switch (reg & REG_CTL_MODE_MASK) {
+ case REG_CTL_MODE_INPUT:
+ return GPIOF_INPUT;
+ case REG_CTL_MODE_INOUT: /* Fallthrough */
+ case REG_CTL_MODE_OUTPUT:
+ return GPIOF_OUTPUT;
+ default:
+ return GPIOF_UNKNOWN;
+ }
+}
+
+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);
+ int reg;
+
+ reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
+ if (reg < 0)
+ return reg;
+
+ return !!(reg & REG_STATUS_VAL_MASK);
+}
+
+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);
+
+ /* Set the output value of the gpio */
+ return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_OUTPUT_MASK, !!value);
+}
+
+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,
+};
+
+static int qcom_gpio_probe(struct udevice *dev)
+{
+ struct qcom_gpio_bank *priv = dev_get_priv(dev);
+ int reg;
+
+ priv->pid = dev_read_addr(dev);
+ if (priv->pid == FDT_ADDR_T_NONE)
+ return log_msg_ret("bad address", -EINVAL);
+
+ /* Do a sanity check */
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
+ if (reg != 0x10)
+ return log_msg_ret("bad type", -ENXIO);
+
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
+ if (reg != 0x5 && reg != 0x1)
+ return log_msg_ret("bad subtype", -ENXIO);
+
+ return 0;
+}
+
+static int qcom_gpio_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+ if (uc_priv->bank_name == NULL)
+ uc_priv->bank_name = "qcom_pmic";
+
+ return 0;
+}
+
+static const struct udevice_id qcom_gpio_ids[] = {
+ { .compatible = "qcom,pm8916-gpio" },
+ { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
+ { .compatible = "qcom,pm8998-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(qcom_pmic_gpio) = {
+ .name = "qcom_pmic_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = qcom_gpio_ids,
+ .of_to_plat = qcom_gpio_of_to_plat,
+ .probe = qcom_gpio_probe,
+ .ops = &qcom_gpio_ops,
+ .priv_auto = sizeof(struct qcom_gpio_bank),
+};
+
+
+/* Add pmic buttons as GPIO as well - there is no generic way for now */
+#define PON_INT_RT_STS 0x10
+#define KPDPWR_ON_INT_BIT 0
+#define RESIN_ON_INT_BIT 1
+
+static int qcom_pwrkey_get_function(struct udevice *dev, unsigned offset)
+{
+ return GPIOF_INPUT;
+}
+
+static int qcom_pwrkey_get_value(struct udevice *dev, unsigned offset)
+{
+ struct qcom_gpio_bank *priv = dev_get_priv(dev);
+
+ int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
+
+ if (reg < 0)
+ return 0;
+
+ switch (offset) {
+ case 0: /* Power button */
+ return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
+ break;
+ case 1: /* Reset button */
+ default:
+ return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
+ break;
+ }
+}
+
+static const struct dm_gpio_ops qcom_pwrkey_ops = {
+ .get_value = qcom_pwrkey_get_value,
+ .get_function = qcom_pwrkey_get_function,
+};
+
+static int qcom_pwrkey_probe(struct udevice *dev)
+{
+ struct qcom_gpio_bank *priv = dev_get_priv(dev);
+ int reg;
+
+ priv->pid = dev_read_addr(dev);
+ if (priv->pid == FDT_ADDR_T_NONE)
+ return log_msg_ret("bad address", -EINVAL);
+
+ /* Do a sanity check */
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
+ if (reg != 0x1)
+ return log_msg_ret("bad type", -ENXIO);
+
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
+ if ((reg & 0x5) == 0)
+ return log_msg_ret("bad subtype", -ENXIO);
+
+ return 0;
+}
+
+static int qcom_pwrkey_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = 2;
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+ if (uc_priv->bank_name == NULL)
+ uc_priv->bank_name = "pwkey_qcom";
+
+ return 0;
+}
+
+static const struct udevice_id qcom_pwrkey_ids[] = {
+ { .compatible = "qcom,pm8916-pwrkey" },
+ { .compatible = "qcom,pm8994-pwrkey" },
+ { .compatible = "qcom,pm8998-pwrkey" },
+ { }
+};
+
+U_BOOT_DRIVER(pwrkey_qcom) = {
+ .name = "pwrkey_qcom",
+ .id = UCLASS_GPIO,
+ .of_match = qcom_pwrkey_ids,
+ .of_to_plat = qcom_pwrkey_of_to_plat,
+ .probe = qcom_pwrkey_probe,
+ .ops = &qcom_pwrkey_ops,
+ .priv_auto = sizeof(struct qcom_gpio_bank),
+};
- MUIC
- Others
-config PMIC_PM8916
- bool "Enable Driver Model for Qualcomm PM8916 PMIC"
+config PMIC_QCOM
+ bool "Enable Driver Model for Qualcomm generic PMIC"
---help---
- The PM8916 is a PMIC connected to one (or several) processors
+ The Qcom PMIC is connected to one (or several) processors
with SPMI bus. It has 2 slaves with several peripherals:
- 18x LDO
- 4x GPIO
- Vibrator drivers
- Others
- Driver binding info: doc/device-tree-bindings/pmic/pm8916.txt
+ Driver binding info: doc/device-tree-bindings/pmic/qcom,spmi-pmic.txt
config PMIC_RK8XX
bool "Enable support for Rockchip PMIC RK8XX"
obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
obj-$(CONFIG_$(SPL_)PMIC_AXP) += axp.o
obj-$(CONFIG_PMIC_MAX8997) += max8997.o
-obj-$(CONFIG_PMIC_PM8916) += pm8916.o
+obj-$(CONFIG_PMIC_QCOM) += pmic_qcom.o
obj-$(CONFIG_$(SPL_TPL_)PMIC_RK8XX) += rk8xx.o
obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Qualcomm pm8916 pmic driver
- *
- */
-#include <common.h>
-#include <dm.h>
-#include <power/pmic.h>
-#include <spmi/spmi.h>
-
-#define PID_SHIFT 8
-#define PID_MASK (0xFF << PID_SHIFT)
-#define REG_MASK 0xFF
-
-struct pm8916_priv {
- uint32_t usid; /* Slave ID on SPMI bus */
-};
-
-static int pm8916_reg_count(struct udevice *dev)
-{
- return 0xFFFF;
-}
-
-static int pm8916_write(struct udevice *dev, uint reg, const uint8_t *buff,
- int len)
-{
- struct pm8916_priv *priv = dev_get_priv(dev);
-
- if (len != 1)
- return -EINVAL;
-
- return spmi_reg_write(dev->parent, priv->usid,
- (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK,
- *buff);
-}
-
-static int pm8916_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
-{
- struct pm8916_priv *priv = dev_get_priv(dev);
- int val;
-
- if (len != 1)
- return -EINVAL;
-
- val = spmi_reg_read(dev->parent, priv->usid,
- (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK);
-
- if (val < 0)
- return val;
- *buff = val;
- return 0;
-}
-
-static struct dm_pmic_ops pm8916_ops = {
- .reg_count = pm8916_reg_count,
- .read = pm8916_read,
- .write = pm8916_write,
-};
-
-static const struct udevice_id pm8916_ids[] = {
- { .compatible = "qcom,spmi-pmic" },
- { }
-};
-
-static int pm8916_probe(struct udevice *dev)
-{
- struct pm8916_priv *priv = dev_get_priv(dev);
-
- priv->usid = dev_read_addr(dev);
-
- if (priv->usid == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- return 0;
-}
-
-U_BOOT_DRIVER(pmic_pm8916) = {
- .name = "pmic_pm8916",
- .id = UCLASS_PMIC,
- .of_match = pm8916_ids,
- .bind = dm_scan_fdt_dev,
- .probe = pm8916_probe,
- .ops = &pm8916_ops,
- .priv_auto = sizeof(struct pm8916_priv),
-};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm generic pmic driver
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+
+#define PID_SHIFT 8
+#define PID_MASK (0xFF << PID_SHIFT)
+#define REG_MASK 0xFF
+
+struct pmic_qcom_priv {
+ uint32_t usid; /* Slave ID on SPMI bus */
+};
+
+static int pmic_qcom_reg_count(struct udevice *dev)
+{
+ return 0xFFFF;
+}
+
+static int pmic_qcom_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ struct pmic_qcom_priv *priv = dev_get_priv(dev);
+
+ if (len != 1)
+ return -EINVAL;
+
+ return spmi_reg_write(dev->parent, priv->usid,
+ (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK,
+ *buff);
+}
+
+static int pmic_qcom_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ struct pmic_qcom_priv *priv = dev_get_priv(dev);
+ int val;
+
+ if (len != 1)
+ return -EINVAL;
+
+ val = spmi_reg_read(dev->parent, priv->usid,
+ (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK);
+
+ if (val < 0)
+ return val;
+ *buff = val;
+ return 0;
+}
+
+static struct dm_pmic_ops pmic_qcom_ops = {
+ .reg_count = pmic_qcom_reg_count,
+ .read = pmic_qcom_read,
+ .write = pmic_qcom_write,
+};
+
+static const struct udevice_id pmic_qcom_ids[] = {
+ { .compatible = "qcom,spmi-pmic" },
+ { }
+};
+
+static int pmic_qcom_probe(struct udevice *dev)
+{
+ struct pmic_qcom_priv *priv = dev_get_priv(dev);
+
+ priv->usid = dev_read_addr(dev);
+
+ if (priv->usid == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(pmic_qcom) = {
+ .name = "pmic_qcom",
+ .id = UCLASS_PMIC,
+ .of_match = pmic_qcom_ids,
+ .bind = dm_scan_fdt_dev,
+ .probe = pmic_qcom_probe,
+ .ops = &pmic_qcom_ops,
+ .priv_auto = sizeof(struct pmic_qcom_priv),
+};