311 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.4 */5 6#include <linux/device.h>7#include <linux/errno.h>8#include <linux/gfp.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/of_device.h>13#include <linux/of_platform.h>14#include <linux/spmi.h>15#include <linux/types.h>16#include <linux/regmap.h>17#include <soc/qcom/qcom-spmi-pmic.h>18 19#define PMIC_REV2 0x10120#define PMIC_REV3 0x10221#define PMIC_REV4 0x10322#define PMIC_TYPE 0x10423#define PMIC_SUBTYPE 0x10524#define PMIC_FAB_ID 0x1f225 26#define PMIC_TYPE_VALUE 0x5127 28#define PMIC_REV4_V2 0x0229 30struct qcom_spmi_dev {31 int num_usids;32 struct qcom_spmi_pmic pmic;33};34 35static DEFINE_MUTEX(pmic_spmi_revid_lock);36 37#define N_USIDS(n) ((void *)n)38 39static const struct of_device_id pmic_spmi_id_table[] = {40 { .compatible = "qcom,pm660", .data = N_USIDS(2) },41 { .compatible = "qcom,pm660l", .data = N_USIDS(2) },42 { .compatible = "qcom,pm8004", .data = N_USIDS(2) },43 { .compatible = "qcom,pm8005", .data = N_USIDS(2) },44 { .compatible = "qcom,pm8019", .data = N_USIDS(2) },45 { .compatible = "qcom,pm8028", .data = N_USIDS(2) },46 { .compatible = "qcom,pm8110", .data = N_USIDS(2) },47 { .compatible = "qcom,pm8150", .data = N_USIDS(2) },48 { .compatible = "qcom,pm8150b", .data = N_USIDS(2) },49 { .compatible = "qcom,pm8150c", .data = N_USIDS(2) },50 { .compatible = "qcom,pm8150l", .data = N_USIDS(2) },51 { .compatible = "qcom,pm8226", .data = N_USIDS(2) },52 { .compatible = "qcom,pm8841", .data = N_USIDS(2) },53 { .compatible = "qcom,pm8901", .data = N_USIDS(2) },54 { .compatible = "qcom,pm8909", .data = N_USIDS(2) },55 { .compatible = "qcom,pm8916", .data = N_USIDS(2) },56 { .compatible = "qcom,pm8937", .data = N_USIDS(2) },57 { .compatible = "qcom,pm8941", .data = N_USIDS(2) },58 { .compatible = "qcom,pm8950", .data = N_USIDS(2) },59 { .compatible = "qcom,pm8994", .data = N_USIDS(2) },60 { .compatible = "qcom,pm8998", .data = N_USIDS(2) },61 { .compatible = "qcom,pma8084", .data = N_USIDS(2) },62 { .compatible = "qcom,pmd9635", .data = N_USIDS(2) },63 { .compatible = "qcom,pmi8950", .data = N_USIDS(2) },64 { .compatible = "qcom,pmi8962", .data = N_USIDS(2) },65 { .compatible = "qcom,pmi8994", .data = N_USIDS(2) },66 { .compatible = "qcom,pmi8998", .data = N_USIDS(2) },67 { .compatible = "qcom,pmk8002", .data = N_USIDS(2) },68 { .compatible = "qcom,pmp8074", .data = N_USIDS(2) },69 { .compatible = "qcom,smb2351", .data = N_USIDS(2) },70 { .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) },71 { }72};73 74/*75 * A PMIC can be represented by multiple SPMI devices, but76 * only the base PMIC device will contain a reference to77 * the revision information.78 *79 * This function takes a pointer to a pmic device and80 * returns a pointer to the base PMIC device.81 *82 * This only supports PMICs with 1 or 2 USIDs.83 */84static struct spmi_device *qcom_pmic_get_base_usid(struct spmi_device *sdev, struct qcom_spmi_dev *ctx)85{86 struct device_node *spmi_bus;87 int function_parent_usid, ret;88 u32 pmic_addr;89 90 /*91 * Quick return if the function device is already in the base92 * USID. This will always be hit for PMICs with only 1 USID.93 */94 if (sdev->usid % ctx->num_usids == 0) {95 get_device(&sdev->dev);96 return sdev;97 }98 99 function_parent_usid = sdev->usid;100 101 /*102 * Walk through the list of PMICs until we find the sibling USID.103 * The goal is to find the first USID which is less than the104 * number of USIDs in the PMIC array, e.g. for a PMIC with 2 USIDs105 * where the function device is under USID 3, we want to find the106 * device for USID 2.107 */108 spmi_bus = of_get_parent(sdev->dev.of_node);109 sdev = ERR_PTR(-ENODATA);110 for_each_child_of_node_scoped(spmi_bus, child) {111 ret = of_property_read_u32_index(child, "reg", 0, &pmic_addr);112 if (ret) {113 sdev = ERR_PTR(ret);114 break;115 }116 117 if (pmic_addr == function_parent_usid - (ctx->num_usids - 1)) {118 sdev = spmi_find_device_by_of_node(child);119 if (!sdev) {120 /*121 * If the base USID for this PMIC hasn't been122 * registered yet then we need to defer.123 */124 sdev = ERR_PTR(-EPROBE_DEFER);125 }126 break;127 }128 }129 130 of_node_put(spmi_bus);131 132 return sdev;133}134 135static int pmic_spmi_get_base_revid(struct spmi_device *sdev, struct qcom_spmi_dev *ctx)136{137 struct qcom_spmi_dev *base_ctx;138 struct spmi_device *base;139 int ret = 0;140 141 base = qcom_pmic_get_base_usid(sdev, ctx);142 if (IS_ERR(base))143 return PTR_ERR(base);144 145 /*146 * Copy revid info from base device if it has probed and is still147 * bound to its driver.148 */149 mutex_lock(&pmic_spmi_revid_lock);150 base_ctx = spmi_device_get_drvdata(base);151 if (!base_ctx) {152 ret = -EPROBE_DEFER;153 goto out_unlock;154 }155 memcpy(&ctx->pmic, &base_ctx->pmic, sizeof(ctx->pmic));156out_unlock:157 mutex_unlock(&pmic_spmi_revid_lock);158 159 put_device(&base->dev);160 161 return ret;162}163 164static int pmic_spmi_load_revid(struct regmap *map, struct device *dev,165 struct qcom_spmi_pmic *pmic)166{167 int ret;168 169 ret = regmap_read(map, PMIC_TYPE, &pmic->type);170 if (ret < 0)171 return ret;172 173 if (pmic->type != PMIC_TYPE_VALUE)174 return ret;175 176 ret = regmap_read(map, PMIC_SUBTYPE, &pmic->subtype);177 if (ret < 0)178 return ret;179 180 pmic->name = of_match_device(pmic_spmi_id_table, dev)->compatible;181 182 ret = regmap_read(map, PMIC_REV2, &pmic->rev2);183 if (ret < 0)184 return ret;185 186 ret = regmap_read(map, PMIC_REV3, &pmic->minor);187 if (ret < 0)188 return ret;189 190 ret = regmap_read(map, PMIC_REV4, &pmic->major);191 if (ret < 0)192 return ret;193 194 if (pmic->subtype == PMI8998_SUBTYPE || pmic->subtype == PM660_SUBTYPE) {195 ret = regmap_read(map, PMIC_FAB_ID, &pmic->fab_id);196 if (ret < 0)197 return ret;198 }199 200 /*201 * In early versions of PM8941 and PM8226, the major revision number202 * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).203 * Increment the major revision number here if the chip is an early204 * version of PM8941 or PM8226.205 */206 if ((pmic->subtype == PM8941_SUBTYPE || pmic->subtype == PM8226_SUBTYPE) &&207 pmic->major < PMIC_REV4_V2)208 pmic->major++;209 210 if (pmic->subtype == PM8110_SUBTYPE)211 pmic->minor = pmic->rev2;212 213 dev_dbg(dev, "%x: %s v%d.%d\n",214 pmic->subtype, pmic->name, pmic->major, pmic->minor);215 216 return 0;217}218 219/**220 * qcom_pmic_get() - Get a pointer to the base PMIC device221 *222 * This function takes a struct device for a driver which is a child of a PMIC.223 * And locates the PMIC revision information for it.224 *225 * @dev: the pmic function device226 * @return: the struct qcom_spmi_pmic* pointer associated with the function device227 */228const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev)229{230 struct spmi_device *sdev;231 struct qcom_spmi_dev *spmi;232 233 /*234 * Make sure the device is actually a child of a PMIC235 */236 if (!of_match_device(pmic_spmi_id_table, dev->parent))237 return ERR_PTR(-EINVAL);238 239 sdev = to_spmi_device(dev->parent);240 spmi = dev_get_drvdata(&sdev->dev);241 242 return &spmi->pmic;243}244EXPORT_SYMBOL_GPL(qcom_pmic_get);245 246static const struct regmap_config spmi_regmap_config = {247 .reg_bits = 16,248 .val_bits = 8,249 .max_register = 0xffff,250 .fast_io = true,251};252 253static int pmic_spmi_probe(struct spmi_device *sdev)254{255 struct regmap *regmap;256 struct qcom_spmi_dev *ctx;257 int ret;258 259 regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);260 if (IS_ERR(regmap))261 return PTR_ERR(regmap);262 263 ctx = devm_kzalloc(&sdev->dev, sizeof(*ctx), GFP_KERNEL);264 if (!ctx)265 return -ENOMEM;266 267 ctx->num_usids = (uintptr_t)device_get_match_data(&sdev->dev);268 269 /* Only the first slave id for a PMIC contains this information */270 if (sdev->usid % ctx->num_usids == 0) {271 ret = pmic_spmi_load_revid(regmap, &sdev->dev, &ctx->pmic);272 if (ret < 0)273 return ret;274 } else {275 ret = pmic_spmi_get_base_revid(sdev, ctx);276 if (ret)277 return ret;278 }279 280 mutex_lock(&pmic_spmi_revid_lock);281 spmi_device_set_drvdata(sdev, ctx);282 mutex_unlock(&pmic_spmi_revid_lock);283 284 return devm_of_platform_populate(&sdev->dev);285}286 287static void pmic_spmi_remove(struct spmi_device *sdev)288{289 mutex_lock(&pmic_spmi_revid_lock);290 spmi_device_set_drvdata(sdev, NULL);291 mutex_unlock(&pmic_spmi_revid_lock);292}293 294MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);295 296static struct spmi_driver pmic_spmi_driver = {297 .probe = pmic_spmi_probe,298 .remove = pmic_spmi_remove,299 .driver = {300 .name = "pmic-spmi",301 .of_match_table = pmic_spmi_id_table,302 },303};304module_spmi_driver(pmic_spmi_driver);305 306MODULE_DESCRIPTION("Qualcomm SPMI PMIC driver");307MODULE_ALIAS("spmi:spmi-pmic");308MODULE_LICENSE("GPL v2");309MODULE_AUTHOR("Josh Cartwright <joshc@codeaurora.org>");310MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");311