1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Device driver for Hi6421 PMIC |
4 | * |
5 | * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. |
6 | * http://www.hisilicon.com |
7 | * Copyright (c) <2013-2017> Linaro Ltd. |
8 | * https://www.linaro.org |
9 | * |
10 | * Author: Guodong Xu <guodong.xu@linaro.org> |
11 | */ |
12 | |
13 | #include <linux/device.h> |
14 | #include <linux/err.h> |
15 | #include <linux/mfd/core.h> |
16 | #include <linux/mfd/hi6421-pmic.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/property.h> |
21 | #include <linux/regmap.h> |
22 | |
23 | static const struct mfd_cell hi6421_devs[] = { |
24 | { .name = "hi6421-regulator" , }, |
25 | }; |
26 | |
27 | static const struct mfd_cell hi6421v530_devs[] = { |
28 | { .name = "hi6421v530-regulator" , }, |
29 | }; |
30 | |
31 | static const struct regmap_config hi6421_regmap_config = { |
32 | .reg_bits = 32, |
33 | .reg_stride = 4, |
34 | .val_bits = 8, |
35 | .max_register = HI6421_REG_TO_BUS_ADDR(HI6421_REG_MAX), |
36 | }; |
37 | |
38 | static const struct of_device_id of_hi6421_pmic_match[] = { |
39 | { |
40 | .compatible = "hisilicon,hi6421-pmic" , |
41 | .data = (void *)HI6421 |
42 | }, |
43 | { |
44 | .compatible = "hisilicon,hi6421v530-pmic" , |
45 | .data = (void *)HI6421_V530 |
46 | }, |
47 | { }, |
48 | }; |
49 | MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match); |
50 | |
51 | static int hi6421_pmic_probe(struct platform_device *pdev) |
52 | { |
53 | struct hi6421_pmic *pmic; |
54 | const struct mfd_cell *subdevs; |
55 | enum hi6421_type type; |
56 | void __iomem *base; |
57 | int n_subdevs, ret; |
58 | |
59 | type = (uintptr_t)device_get_match_data(dev: &pdev->dev); |
60 | |
61 | pmic = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pmic), GFP_KERNEL); |
62 | if (!pmic) |
63 | return -ENOMEM; |
64 | |
65 | base = devm_platform_get_and_ioremap_resource(pdev, index: 0, NULL); |
66 | if (IS_ERR(ptr: base)) |
67 | return PTR_ERR(ptr: base); |
68 | |
69 | pmic->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, |
70 | &hi6421_regmap_config); |
71 | if (IS_ERR(ptr: pmic->regmap)) { |
72 | dev_err(&pdev->dev, "Failed to initialise Regmap: %ld\n" , |
73 | PTR_ERR(pmic->regmap)); |
74 | return PTR_ERR(ptr: pmic->regmap); |
75 | } |
76 | |
77 | platform_set_drvdata(pdev, data: pmic); |
78 | |
79 | switch (type) { |
80 | case HI6421: |
81 | /* set over-current protection debounce 8ms */ |
82 | regmap_update_bits(map: pmic->regmap, HI6421_OCP_DEB_CTRL_REG, |
83 | mask: (HI6421_OCP_DEB_SEL_MASK |
84 | | HI6421_OCP_EN_DEBOUNCE_MASK |
85 | | HI6421_OCP_AUTO_STOP_MASK), |
86 | val: (HI6421_OCP_DEB_SEL_8MS |
87 | | HI6421_OCP_EN_DEBOUNCE_ENABLE)); |
88 | |
89 | subdevs = hi6421_devs; |
90 | n_subdevs = ARRAY_SIZE(hi6421_devs); |
91 | break; |
92 | case HI6421_V530: |
93 | subdevs = hi6421v530_devs; |
94 | n_subdevs = ARRAY_SIZE(hi6421v530_devs); |
95 | break; |
96 | default: |
97 | dev_err(&pdev->dev, "Unknown device type %d\n" , |
98 | (unsigned int)type); |
99 | return -EINVAL; |
100 | } |
101 | |
102 | ret = devm_mfd_add_devices(dev: &pdev->dev, PLATFORM_DEVID_NONE, |
103 | cells: subdevs, n_devs: n_subdevs, NULL, irq_base: 0, NULL); |
104 | if (ret) { |
105 | dev_err(&pdev->dev, "Failed to add child devices: %d\n" , ret); |
106 | return ret; |
107 | } |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static struct platform_driver hi6421_pmic_driver = { |
113 | .driver = { |
114 | .name = "hi6421_pmic" , |
115 | .of_match_table = of_hi6421_pmic_match, |
116 | }, |
117 | .probe = hi6421_pmic_probe, |
118 | }; |
119 | module_platform_driver(hi6421_pmic_driver); |
120 | |
121 | MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>" ); |
122 | MODULE_DESCRIPTION("Hi6421 PMIC driver" ); |
123 | MODULE_LICENSE("GPL v2" ); |
124 | |