1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28bdf87b4SGuodong Xu /*
3ec58871fSGuodong Xu * Device driver for Hi6421 PMIC
48bdf87b4SGuodong Xu *
58bdf87b4SGuodong Xu * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
68bdf87b4SGuodong Xu * http://www.hisilicon.com
7ec58871fSGuodong Xu * Copyright (c) <2013-2017> Linaro Ltd.
84f4ed454SAlexander A. Klimov * https://www.linaro.org
98bdf87b4SGuodong Xu *
108bdf87b4SGuodong Xu * Author: Guodong Xu <guodong.xu@linaro.org>
118bdf87b4SGuodong Xu */
128bdf87b4SGuodong Xu
138bdf87b4SGuodong Xu #include <linux/device.h>
148bdf87b4SGuodong Xu #include <linux/err.h>
158bdf87b4SGuodong Xu #include <linux/mfd/core.h>
16ec58871fSGuodong Xu #include <linux/mfd/hi6421-pmic.h>
178bdf87b4SGuodong Xu #include <linux/module.h>
18ec58871fSGuodong Xu #include <linux/of_device.h>
198bdf87b4SGuodong Xu #include <linux/platform_device.h>
208bdf87b4SGuodong Xu #include <linux/regmap.h>
218bdf87b4SGuodong Xu
228bdf87b4SGuodong Xu static const struct mfd_cell hi6421_devs[] = {
238bdf87b4SGuodong Xu { .name = "hi6421-regulator", },
248bdf87b4SGuodong Xu };
258bdf87b4SGuodong Xu
26ec58871fSGuodong Xu static const struct mfd_cell hi6421v530_devs[] = {
27ec58871fSGuodong Xu { .name = "hi6421v530-regulator", },
28ec58871fSGuodong Xu };
29ec58871fSGuodong Xu
307f9e3febSKrzysztof Kozlowski static const struct regmap_config hi6421_regmap_config = {
318bdf87b4SGuodong Xu .reg_bits = 32,
328bdf87b4SGuodong Xu .reg_stride = 4,
338bdf87b4SGuodong Xu .val_bits = 8,
348bdf87b4SGuodong Xu .max_register = HI6421_REG_TO_BUS_ADDR(HI6421_REG_MAX),
358bdf87b4SGuodong Xu };
368bdf87b4SGuodong Xu
37ec58871fSGuodong Xu static const struct of_device_id of_hi6421_pmic_match[] = {
38ec58871fSGuodong Xu {
39ec58871fSGuodong Xu .compatible = "hisilicon,hi6421-pmic",
40ec58871fSGuodong Xu .data = (void *)HI6421
41ec58871fSGuodong Xu },
42ec58871fSGuodong Xu {
43ec58871fSGuodong Xu .compatible = "hisilicon,hi6421v530-pmic",
44ec58871fSGuodong Xu .data = (void *)HI6421_V530
45ec58871fSGuodong Xu },
46ec58871fSGuodong Xu { },
47ec58871fSGuodong Xu };
48ec58871fSGuodong Xu MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match);
49ec58871fSGuodong Xu
hi6421_pmic_probe(struct platform_device * pdev)508bdf87b4SGuodong Xu static int hi6421_pmic_probe(struct platform_device *pdev)
518bdf87b4SGuodong Xu {
528bdf87b4SGuodong Xu struct hi6421_pmic *pmic;
53ec58871fSGuodong Xu const struct of_device_id *id;
54ec58871fSGuodong Xu const struct mfd_cell *subdevs;
55ec58871fSGuodong Xu enum hi6421_type type;
568bdf87b4SGuodong Xu void __iomem *base;
57ec58871fSGuodong Xu int n_subdevs, ret;
58ec58871fSGuodong Xu
59ec58871fSGuodong Xu id = of_match_device(of_hi6421_pmic_match, &pdev->dev);
60ec58871fSGuodong Xu if (!id)
61ec58871fSGuodong Xu return -EINVAL;
62*b2ee6a37SKrzysztof Kozlowski type = (uintptr_t)id->data;
638bdf87b4SGuodong Xu
648bdf87b4SGuodong Xu pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
658bdf87b4SGuodong Xu if (!pmic)
668bdf87b4SGuodong Xu return -ENOMEM;
678bdf87b4SGuodong Xu
6874d3de87SYe Xingchen base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
698bdf87b4SGuodong Xu if (IS_ERR(base))
708bdf87b4SGuodong Xu return PTR_ERR(base);
718bdf87b4SGuodong Xu
728bdf87b4SGuodong Xu pmic->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
738bdf87b4SGuodong Xu &hi6421_regmap_config);
748bdf87b4SGuodong Xu if (IS_ERR(pmic->regmap)) {
75568e5476SGuodong Xu dev_err(&pdev->dev, "Failed to initialise Regmap: %ld\n",
76568e5476SGuodong Xu PTR_ERR(pmic->regmap));
778bdf87b4SGuodong Xu return PTR_ERR(pmic->regmap);
788bdf87b4SGuodong Xu }
798bdf87b4SGuodong Xu
80ec58871fSGuodong Xu platform_set_drvdata(pdev, pmic);
81ec58871fSGuodong Xu
82ec58871fSGuodong Xu switch (type) {
83ec58871fSGuodong Xu case HI6421:
848bdf87b4SGuodong Xu /* set over-current protection debounce 8ms */
858bdf87b4SGuodong Xu regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG,
868bdf87b4SGuodong Xu (HI6421_OCP_DEB_SEL_MASK
878bdf87b4SGuodong Xu | HI6421_OCP_EN_DEBOUNCE_MASK
888bdf87b4SGuodong Xu | HI6421_OCP_AUTO_STOP_MASK),
898bdf87b4SGuodong Xu (HI6421_OCP_DEB_SEL_8MS
908bdf87b4SGuodong Xu | HI6421_OCP_EN_DEBOUNCE_ENABLE));
918bdf87b4SGuodong Xu
92ec58871fSGuodong Xu subdevs = hi6421_devs;
93ec58871fSGuodong Xu n_subdevs = ARRAY_SIZE(hi6421_devs);
94ec58871fSGuodong Xu break;
95ec58871fSGuodong Xu case HI6421_V530:
96ec58871fSGuodong Xu subdevs = hi6421v530_devs;
97ec58871fSGuodong Xu n_subdevs = ARRAY_SIZE(hi6421v530_devs);
98ec58871fSGuodong Xu break;
99ec58871fSGuodong Xu default:
100ec58871fSGuodong Xu dev_err(&pdev->dev, "Unknown device type %d\n",
101ec58871fSGuodong Xu (unsigned int)type);
102ec58871fSGuodong Xu return -EINVAL;
103ec58871fSGuodong Xu }
1048bdf87b4SGuodong Xu
105ec58871fSGuodong Xu ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
106ec58871fSGuodong Xu subdevs, n_subdevs, NULL, 0, NULL);
1078bdf87b4SGuodong Xu if (ret) {
108568e5476SGuodong Xu dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
1098bdf87b4SGuodong Xu return ret;
1108bdf87b4SGuodong Xu }
1118bdf87b4SGuodong Xu
1128bdf87b4SGuodong Xu return 0;
1138bdf87b4SGuodong Xu }
1148bdf87b4SGuodong Xu
1158bdf87b4SGuodong Xu static struct platform_driver hi6421_pmic_driver = {
1168bdf87b4SGuodong Xu .driver = {
1178bdf87b4SGuodong Xu .name = "hi6421_pmic",
118ec58871fSGuodong Xu .of_match_table = of_hi6421_pmic_match,
1198bdf87b4SGuodong Xu },
1208bdf87b4SGuodong Xu .probe = hi6421_pmic_probe,
1218bdf87b4SGuodong Xu };
1228bdf87b4SGuodong Xu module_platform_driver(hi6421_pmic_driver);
1238bdf87b4SGuodong Xu
1248bdf87b4SGuodong Xu MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
1258bdf87b4SGuodong Xu MODULE_DESCRIPTION("Hi6421 PMIC driver");
1268bdf87b4SGuodong Xu MODULE_LICENSE("GPL v2");
127