1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/spmi.h>
9*4882a593Smuzhiyun #include <linux/regmap.h>
10*4882a593Smuzhiyun #include <linux/of_platform.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define PMIC_REV2 0x101
13*4882a593Smuzhiyun #define PMIC_REV3 0x102
14*4882a593Smuzhiyun #define PMIC_REV4 0x103
15*4882a593Smuzhiyun #define PMIC_TYPE 0x104
16*4882a593Smuzhiyun #define PMIC_SUBTYPE 0x105
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define PMIC_TYPE_VALUE 0x51
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define COMMON_SUBTYPE 0x00
21*4882a593Smuzhiyun #define PM8941_SUBTYPE 0x01
22*4882a593Smuzhiyun #define PM8841_SUBTYPE 0x02
23*4882a593Smuzhiyun #define PM8019_SUBTYPE 0x03
24*4882a593Smuzhiyun #define PM8226_SUBTYPE 0x04
25*4882a593Smuzhiyun #define PM8110_SUBTYPE 0x05
26*4882a593Smuzhiyun #define PMA8084_SUBTYPE 0x06
27*4882a593Smuzhiyun #define PMI8962_SUBTYPE 0x07
28*4882a593Smuzhiyun #define PMD9635_SUBTYPE 0x08
29*4882a593Smuzhiyun #define PM8994_SUBTYPE 0x09
30*4882a593Smuzhiyun #define PMI8994_SUBTYPE 0x0a
31*4882a593Smuzhiyun #define PM8916_SUBTYPE 0x0b
32*4882a593Smuzhiyun #define PM8004_SUBTYPE 0x0c
33*4882a593Smuzhiyun #define PM8909_SUBTYPE 0x0d
34*4882a593Smuzhiyun #define PM8950_SUBTYPE 0x10
35*4882a593Smuzhiyun #define PMI8950_SUBTYPE 0x11
36*4882a593Smuzhiyun #define PM8998_SUBTYPE 0x14
37*4882a593Smuzhiyun #define PMI8998_SUBTYPE 0x15
38*4882a593Smuzhiyun #define PM8005_SUBTYPE 0x18
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const struct of_device_id pmic_spmi_id_table[] = {
41*4882a593Smuzhiyun { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE },
42*4882a593Smuzhiyun { .compatible = "qcom,pm8941", .data = (void *)PM8941_SUBTYPE },
43*4882a593Smuzhiyun { .compatible = "qcom,pm8841", .data = (void *)PM8841_SUBTYPE },
44*4882a593Smuzhiyun { .compatible = "qcom,pm8019", .data = (void *)PM8019_SUBTYPE },
45*4882a593Smuzhiyun { .compatible = "qcom,pm8226", .data = (void *)PM8226_SUBTYPE },
46*4882a593Smuzhiyun { .compatible = "qcom,pm8110", .data = (void *)PM8110_SUBTYPE },
47*4882a593Smuzhiyun { .compatible = "qcom,pma8084", .data = (void *)PMA8084_SUBTYPE },
48*4882a593Smuzhiyun { .compatible = "qcom,pmi8962", .data = (void *)PMI8962_SUBTYPE },
49*4882a593Smuzhiyun { .compatible = "qcom,pmd9635", .data = (void *)PMD9635_SUBTYPE },
50*4882a593Smuzhiyun { .compatible = "qcom,pm8994", .data = (void *)PM8994_SUBTYPE },
51*4882a593Smuzhiyun { .compatible = "qcom,pmi8994", .data = (void *)PMI8994_SUBTYPE },
52*4882a593Smuzhiyun { .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE },
53*4882a593Smuzhiyun { .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE },
54*4882a593Smuzhiyun { .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE },
55*4882a593Smuzhiyun { .compatible = "qcom,pm8950", .data = (void *)PM8950_SUBTYPE },
56*4882a593Smuzhiyun { .compatible = "qcom,pmi8950", .data = (void *)PMI8950_SUBTYPE },
57*4882a593Smuzhiyun { .compatible = "qcom,pm8998", .data = (void *)PM8998_SUBTYPE },
58*4882a593Smuzhiyun { .compatible = "qcom,pmi8998", .data = (void *)PMI8998_SUBTYPE },
59*4882a593Smuzhiyun { .compatible = "qcom,pm8005", .data = (void *)PM8005_SUBTYPE },
60*4882a593Smuzhiyun { }
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun
pmic_spmi_show_revid(struct regmap * map,struct device * dev)63*4882a593Smuzhiyun static void pmic_spmi_show_revid(struct regmap *map, struct device *dev)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun unsigned int rev2, minor, major, type, subtype;
66*4882a593Smuzhiyun const char *name = "unknown";
67*4882a593Smuzhiyun int ret, i;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun ret = regmap_read(map, PMIC_TYPE, &type);
70*4882a593Smuzhiyun if (ret < 0)
71*4882a593Smuzhiyun return;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (type != PMIC_TYPE_VALUE)
74*4882a593Smuzhiyun return;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun ret = regmap_read(map, PMIC_SUBTYPE, &subtype);
77*4882a593Smuzhiyun if (ret < 0)
78*4882a593Smuzhiyun return;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) {
81*4882a593Smuzhiyun if (subtype == (unsigned long)pmic_spmi_id_table[i].data)
82*4882a593Smuzhiyun break;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (i != ARRAY_SIZE(pmic_spmi_id_table))
86*4882a593Smuzhiyun name = pmic_spmi_id_table[i].compatible;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun ret = regmap_read(map, PMIC_REV2, &rev2);
89*4882a593Smuzhiyun if (ret < 0)
90*4882a593Smuzhiyun return;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun ret = regmap_read(map, PMIC_REV3, &minor);
93*4882a593Smuzhiyun if (ret < 0)
94*4882a593Smuzhiyun return;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun ret = regmap_read(map, PMIC_REV4, &major);
97*4882a593Smuzhiyun if (ret < 0)
98*4882a593Smuzhiyun return;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /*
101*4882a593Smuzhiyun * In early versions of PM8941 and PM8226, the major revision number
102*4882a593Smuzhiyun * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
103*4882a593Smuzhiyun * Increment the major revision number here if the chip is an early
104*4882a593Smuzhiyun * version of PM8941 or PM8226.
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) &&
107*4882a593Smuzhiyun major < 0x02)
108*4882a593Smuzhiyun major++;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (subtype == PM8110_SUBTYPE)
111*4882a593Smuzhiyun minor = rev2;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static const struct regmap_config spmi_regmap_config = {
117*4882a593Smuzhiyun .reg_bits = 16,
118*4882a593Smuzhiyun .val_bits = 8,
119*4882a593Smuzhiyun .max_register = 0xffff,
120*4882a593Smuzhiyun .fast_io = true,
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun
pmic_spmi_probe(struct spmi_device * sdev)123*4882a593Smuzhiyun static int pmic_spmi_probe(struct spmi_device *sdev)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct regmap *regmap;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
128*4882a593Smuzhiyun if (IS_ERR(regmap))
129*4882a593Smuzhiyun return PTR_ERR(regmap);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Only the first slave id for a PMIC contains this information */
132*4882a593Smuzhiyun if (sdev->usid % 2 == 0)
133*4882a593Smuzhiyun pmic_spmi_show_revid(regmap, &sdev->dev);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return devm_of_platform_populate(&sdev->dev);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun static struct spmi_driver pmic_spmi_driver = {
141*4882a593Smuzhiyun .probe = pmic_spmi_probe,
142*4882a593Smuzhiyun .driver = {
143*4882a593Smuzhiyun .name = "pmic-spmi",
144*4882a593Smuzhiyun .of_match_table = pmic_spmi_id_table,
145*4882a593Smuzhiyun },
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun module_spmi_driver(pmic_spmi_driver);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun MODULE_DESCRIPTION("Qualcomm SPMI PMIC driver");
150*4882a593Smuzhiyun MODULE_ALIAS("spmi:spmi-pmic");
151*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
152*4882a593Smuzhiyun MODULE_AUTHOR("Josh Cartwright <joshc@codeaurora.org>");
153*4882a593Smuzhiyun MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
154