+ spmi_bus = of_get_parent(sdev->dev.parent->of_node);
+ do {
+ other_usid = of_get_next_child(spmi_bus, other_usid);
+ ret = of_property_read_u32_array(other_usid, "reg", reg, 2);
+ if (ret)
+ return ERR_PTR(ret);
+ sdev = spmi_device_from_of(other_usid);
+ if (sdev == NULL) {
+ /*
+ * If the base USID for this PMIC hasn't probed yet
+ * but the secondary USID has, then we need to defer
+ * the function driver so that it will attempt to
+ * probe again when the base USID is ready.
+ */
+ if (reg[0] == function_parent_usid - 1)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ continue;
+ }
+
+ if (reg[0] == function_parent_usid - 1)
+ return spmi_device_get_drvdata(sdev);
+ } while (other_usid->sibling);
+
+ return ERR_PTR(-ENODATA);
+}
+EXPORT_SYMBOL(qcom_pmic_get);
+
+static inline void pmic_print_info(struct device *dev, struct qcom_spmi_pmic *pmic)
+{
+ dev_dbg(dev, "%x: %s v%d.%d\n",
+ pmic->subtype, pmic->name, pmic->major, pmic->minor);
+}
+
+static int pmic_spmi_load_revid(struct regmap *map, struct device *dev,
+ struct qcom_spmi_pmic *pmic)
{
- unsigned int rev2, minor, major, type, subtype;
- const char *name = "unknown";
int ret, i;
- ret = regmap_read(map, PMIC_TYPE, &type);
+ ret = regmap_read(map, PMIC_TYPE, &pmic->type);
if (ret < 0)
- return;
+ return ret;
- if (type != PMIC_TYPE_VALUE)
- return;
+ if (pmic->type != PMIC_TYPE_VALUE)
+ return ret;
- ret = regmap_read(map, PMIC_SUBTYPE, &subtype);
+ ret = regmap_read(map, PMIC_SUBTYPE, &pmic->subtype);
if (ret < 0)
- return;
+ return ret;
for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) {
- if (subtype == (unsigned long)pmic_spmi_id_table[i].data)
+ if (pmic->subtype == (unsigned long)pmic_spmi_id_table[i].data)
break;
}
if (i != ARRAY_SIZE(pmic_spmi_id_table))
- name = pmic_spmi_id_table[i].compatible;
+ pmic->name = devm_kstrdup_const(dev, pmic_spmi_id_table[i].compatible, GFP_KERNEL);
- ret = regmap_read(map, PMIC_REV2, &rev2);
+ ret = regmap_read(map, PMIC_REV2, &pmic->rev2);
if (ret < 0)
- return;
+ return ret;
- ret = regmap_read(map, PMIC_REV3, &minor);
+ ret = regmap_read(map, PMIC_REV3, &pmic->minor);
if (ret < 0)
- return;
+ return ret;
- ret = regmap_read(map, PMIC_REV4, &major);
+ ret = regmap_read(map, PMIC_REV4, &pmic->major);
if (ret < 0)
- return;
+ return ret;
/*
* In early versions of PM8941 and PM8226, the major revision number
@@ -124,14 +174,16 @@ static void pmic_spmi_show_revid(struct regmap *map, struct device *dev)
* Increment the major revision number here if the chip is an early
* version of PM8941 or PM8226.
*/
- if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) &&
- major < 0x02)
- major++;
+ if ((pmic->subtype == PM8941_SUBTYPE || pmic->subtype == PM8226_SUBTYPE) &&
+ pmic->major < 0x02)
+ pmic->major++;
+
+ if (pmic->subtype == PM8110_SUBTYPE)
+ pmic->minor = pmic->rev2;
- if (subtype == PM8110_SUBTYPE)
- minor = rev2;
+ pmic_print_info(dev, pmic);
- dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor);
+ return 0;
}
static const struct regmap_config spmi_regmap_config = {
@@ -144,14 +196,24 @@ static const struct regmap_config spmi_regmap_config = {
static int pmic_spmi_probe(struct spmi_device *sdev)
{
struct regmap *regmap;
+ struct qcom_spmi_pmic *pmic;
+ int ret;
regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
+ pmic = devm_kzalloc(&sdev->dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
/* Only the first slave id for a PMIC contains this information */
- if (sdev->usid % 2 == 0)
- pmic_spmi_show_revid(regmap, &sdev->dev);
+ if (sdev->usid % 2 == 0) {
+ ret = pmic_spmi_load_revid(regmap, &sdev->dev, pmic);
+ if (ret < 0)
+ return ret;
+ spmi_device_set_drvdata(sdev, pmic);
+ }
return devm_of_platform_populate(&sdev->dev);
}
diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h
new file mode 100644
index 000000000000..a8a77be22cfc
--- /dev/null
+++ b/include/soc/qcom/qcom-spmi-pmic.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2021 Linaro. All rights reserved.
+ * Copyright (c) 2021 Caleb Connolly <caleb.connolly@xxxxxxxxxx>
+ */
+
+#ifndef __QCOM_PMIC_H__
+#define __QCOM_PMIC_H__
+
+#define COMMON_SUBTYPE 0x00
+#define PM8941_SUBTYPE 0x01
+#define PM8841_SUBTYPE 0x02
+#define PM8019_SUBTYPE 0x03
+#define PM8226_SUBTYPE 0x04
+#define PM8110_SUBTYPE 0x05
+#define PMA8084_SUBTYPE 0x06
+#define PMI8962_SUBTYPE 0x07
+#define PMD9635_SUBTYPE 0x08
+#define PM8994_SUBTYPE 0x09
+#define PMI8994_SUBTYPE 0x0a
+#define PM8916_SUBTYPE 0x0b
+#define PM8004_SUBTYPE 0x0c
+#define PM8909_SUBTYPE 0x0d
+#define PM8028_SUBTYPE 0x0e
+#define PM8901_SUBTYPE 0x0f
+#define PM8950_SUBTYPE 0x10
+#define PMI8950_SUBTYPE 0x11
+#define PM8998_SUBTYPE 0x14
+#define PMI8998_SUBTYPE 0x15
+#define PM8005_SUBTYPE 0x18
+#define PM660L_SUBTYPE 0x1A
+#define PM660_SUBTYPE 0x1B
+#define PM8150_SUBTYPE 0x1E
+#define PM8150L_SUBTYPE 0x1f
+#define PM8150B_SUBTYPE 0x20
+#define PMK8002_SUBTYPE 0x21
+#define PM8009_SUBTYPE 0x24
+#define PM8150C_SUBTYPE 0x26
+#define SMB2351_SUBTYPE 0x29
+
+#define PMI8998_FAB_ID_SMIC 0x11
+#define PMI8998_FAB_ID_GF 0x30
+
+#define PM660_FAB_ID_GF 0x0
+#define PM660_FAB_ID_TSMC 0x2
+#define PM660_FAB_ID_MX 0x3
+
+struct qcom_spmi_pmic {
+ unsigned int type;
+ unsigned int subtype;
+ unsigned int major;
+ unsigned int minor;
+ unsigned int rev2;
+ const char *name;
+};
+
+struct device;
+
+const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev);
+
+#endif /* __QCOM_PMIC_H__ */
--
2.35.1