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