1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b52207efSChen Feng /*
3b52207efSChen Feng * Device driver for MFD hi655x PMIC
4b52207efSChen Feng *
507a0b7d6SHao Fang * Copyright (c) 2016 HiSilicon Ltd.
6b52207efSChen Feng *
7b52207efSChen Feng * Authors:
8b52207efSChen Feng * Chen Feng <puck.chen@hisilicon.com>
9b52207efSChen Feng * Fei Wang <w.f@huawei.com>
10b52207efSChen Feng */
11b52207efSChen Feng
12b52207efSChen Feng #include <linux/io.h>
13b52207efSChen Feng #include <linux/interrupt.h>
14b52207efSChen Feng #include <linux/init.h>
15b52207efSChen Feng #include <linux/mfd/core.h>
16b52207efSChen Feng #include <linux/mfd/hi655x-pmic.h>
17b52207efSChen Feng #include <linux/module.h>
187f5aaa4aSMaíra Canal #include <linux/gpio/consumer.h>
19*dc0c386eSRob Herring #include <linux/mod_devicetable.h>
20b52207efSChen Feng #include <linux/platform_device.h>
21b52207efSChen Feng #include <linux/regmap.h>
22b52207efSChen Feng
23b52207efSChen Feng static const struct regmap_irq hi655x_irqs[] = {
249e3d5c99SJohn Stultz { .reg_offset = 0, .mask = OTMP_D1R_INT_MASK },
259e3d5c99SJohn Stultz { .reg_offset = 0, .mask = VSYS_2P5_R_INT_MASK },
269e3d5c99SJohn Stultz { .reg_offset = 0, .mask = VSYS_UV_D3R_INT_MASK },
279e3d5c99SJohn Stultz { .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT_MASK },
289e3d5c99SJohn Stultz { .reg_offset = 0, .mask = PWRON_D4SR_INT_MASK },
299e3d5c99SJohn Stultz { .reg_offset = 0, .mask = PWRON_D20F_INT_MASK },
309e3d5c99SJohn Stultz { .reg_offset = 0, .mask = PWRON_D20R_INT_MASK },
319e3d5c99SJohn Stultz { .reg_offset = 0, .mask = RESERVE_INT_MASK },
32b52207efSChen Feng };
33b52207efSChen Feng
34b52207efSChen Feng static const struct regmap_irq_chip hi655x_irq_chip = {
35b52207efSChen Feng .name = "hi655x-pmic",
36b52207efSChen Feng .irqs = hi655x_irqs,
37b52207efSChen Feng .num_regs = 1,
38b52207efSChen Feng .num_irqs = ARRAY_SIZE(hi655x_irqs),
39b52207efSChen Feng .status_base = HI655X_IRQ_STAT_BASE,
40417e06bbSJohn Stultz .ack_base = HI655X_IRQ_STAT_BASE,
41b52207efSChen Feng .mask_base = HI655X_IRQ_MASK_BASE,
42b52207efSChen Feng };
43b52207efSChen Feng
44b52207efSChen Feng static struct regmap_config hi655x_regmap_config = {
45b52207efSChen Feng .reg_bits = 32,
46b52207efSChen Feng .reg_stride = HI655X_STRIDE,
47b52207efSChen Feng .val_bits = 8,
486afebb70SRafael David Tinoco .max_register = HI655X_BUS_ADDR(0x400) - HI655X_STRIDE,
49b52207efSChen Feng };
50b52207efSChen Feng
51c4a164f4SRikard Falkeborn static const struct resource pwrkey_resources[] = {
52eb10245fSJohn Stultz {
53eb10245fSJohn Stultz .name = "down",
54eb10245fSJohn Stultz .start = PWRON_D20R_INT,
55eb10245fSJohn Stultz .end = PWRON_D20R_INT,
56eb10245fSJohn Stultz .flags = IORESOURCE_IRQ,
57eb10245fSJohn Stultz }, {
58eb10245fSJohn Stultz .name = "up",
59eb10245fSJohn Stultz .start = PWRON_D20F_INT,
60eb10245fSJohn Stultz .end = PWRON_D20F_INT,
61eb10245fSJohn Stultz .flags = IORESOURCE_IRQ,
62eb10245fSJohn Stultz }, {
63eb10245fSJohn Stultz .name = "hold 4s",
64eb10245fSJohn Stultz .start = PWRON_D4SR_INT,
65eb10245fSJohn Stultz .end = PWRON_D4SR_INT,
66eb10245fSJohn Stultz .flags = IORESOURCE_IRQ,
67eb10245fSJohn Stultz },
68eb10245fSJohn Stultz };
69eb10245fSJohn Stultz
70eb10245fSJohn Stultz static const struct mfd_cell hi655x_pmic_devs[] = {
71eb10245fSJohn Stultz {
72eb10245fSJohn Stultz .name = "hi65xx-powerkey",
73eb10245fSJohn Stultz .num_resources = ARRAY_SIZE(pwrkey_resources),
74eb10245fSJohn Stultz .resources = &pwrkey_resources[0],
75eb10245fSJohn Stultz },
76eb10245fSJohn Stultz { .name = "hi655x-regulator", },
77ac03fec1SDaniel Lezcano { .name = "hi655x-clk", },
78eb10245fSJohn Stultz };
79eb10245fSJohn Stultz
hi655x_local_irq_clear(struct regmap * map)80b52207efSChen Feng static void hi655x_local_irq_clear(struct regmap *map)
81b52207efSChen Feng {
82b52207efSChen Feng int i;
83b52207efSChen Feng
84b52207efSChen Feng regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR);
85b52207efSChen Feng for (i = 0; i < HI655X_IRQ_ARRAY; i++) {
86b52207efSChen Feng regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE,
87b52207efSChen Feng HI655X_IRQ_CLR);
88b52207efSChen Feng }
89b52207efSChen Feng }
90b52207efSChen Feng
hi655x_pmic_probe(struct platform_device * pdev)91b52207efSChen Feng static int hi655x_pmic_probe(struct platform_device *pdev)
92b52207efSChen Feng {
93b52207efSChen Feng int ret;
94b52207efSChen Feng struct hi655x_pmic *pmic;
95b52207efSChen Feng struct device *dev = &pdev->dev;
96b52207efSChen Feng void __iomem *base;
97b52207efSChen Feng
98b52207efSChen Feng pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
99b52207efSChen Feng if (!pmic)
100b52207efSChen Feng return -ENOMEM;
101b52207efSChen Feng pmic->dev = dev;
102b52207efSChen Feng
1032459f4dfSYangtao Li base = devm_platform_ioremap_resource(pdev, 0);
1047e28abdaSWei Yongjun if (IS_ERR(base))
1057e28abdaSWei Yongjun return PTR_ERR(base);
106b52207efSChen Feng
107b52207efSChen Feng pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
108b52207efSChen Feng &hi655x_regmap_config);
1097efd105cSAxel Lin if (IS_ERR(pmic->regmap))
1107efd105cSAxel Lin return PTR_ERR(pmic->regmap);
111b52207efSChen Feng
112b52207efSChen Feng regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
113b52207efSChen Feng if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
114b52207efSChen Feng dev_warn(dev, "PMU version %d unsupported\n", pmic->ver);
115b52207efSChen Feng return -EINVAL;
116b52207efSChen Feng }
117b52207efSChen Feng
118b52207efSChen Feng hi655x_local_irq_clear(pmic->regmap);
119b52207efSChen Feng
1207f5aaa4aSMaíra Canal pmic->gpio = devm_gpiod_get_optional(dev, "pmic", GPIOD_IN);
1217f5aaa4aSMaíra Canal if (IS_ERR(pmic->gpio))
1227f5aaa4aSMaíra Canal return dev_err_probe(dev, PTR_ERR(pmic->gpio),
1237f5aaa4aSMaíra Canal "Failed to request hi655x pmic-gpio");
124b52207efSChen Feng
1257f5aaa4aSMaíra Canal ret = regmap_add_irq_chip(pmic->regmap, gpiod_to_irq(pmic->gpio),
126b52207efSChen Feng IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0,
127b52207efSChen Feng &hi655x_irq_chip, &pmic->irq_data);
128b52207efSChen Feng if (ret) {
129b52207efSChen Feng dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret);
130b52207efSChen Feng return ret;
131b52207efSChen Feng }
132b52207efSChen Feng
133b52207efSChen Feng platform_set_drvdata(pdev, pmic);
134b52207efSChen Feng
135b52207efSChen Feng ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs,
136eb10245fSJohn Stultz ARRAY_SIZE(hi655x_pmic_devs), NULL, 0,
137eb10245fSJohn Stultz regmap_irq_get_domain(pmic->irq_data));
138b52207efSChen Feng if (ret) {
139b52207efSChen Feng dev_err(dev, "Failed to register device %d\n", ret);
1407f5aaa4aSMaíra Canal regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
141b52207efSChen Feng return ret;
142b52207efSChen Feng }
143b52207efSChen Feng
144b52207efSChen Feng return 0;
145b52207efSChen Feng }
146b52207efSChen Feng
hi655x_pmic_remove(struct platform_device * pdev)147b52207efSChen Feng static int hi655x_pmic_remove(struct platform_device *pdev)
148b52207efSChen Feng {
149b52207efSChen Feng struct hi655x_pmic *pmic = platform_get_drvdata(pdev);
150b52207efSChen Feng
1517f5aaa4aSMaíra Canal regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
152b52207efSChen Feng mfd_remove_devices(&pdev->dev);
153b52207efSChen Feng return 0;
154b52207efSChen Feng }
155b52207efSChen Feng
156b52207efSChen Feng static const struct of_device_id hi655x_pmic_match[] = {
157b52207efSChen Feng { .compatible = "hisilicon,hi655x-pmic", },
158b52207efSChen Feng {},
159b52207efSChen Feng };
160e45b6c80SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
161b52207efSChen Feng
162b52207efSChen Feng static struct platform_driver hi655x_pmic_driver = {
163b52207efSChen Feng .driver = {
164b52207efSChen Feng .name = "hi655x-pmic",
165*dc0c386eSRob Herring .of_match_table = hi655x_pmic_match,
166b52207efSChen Feng },
167b52207efSChen Feng .probe = hi655x_pmic_probe,
168b52207efSChen Feng .remove = hi655x_pmic_remove,
169b52207efSChen Feng };
170b52207efSChen Feng module_platform_driver(hi655x_pmic_driver);
171b52207efSChen Feng
172b52207efSChen Feng MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
173b52207efSChen Feng MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver");
174b52207efSChen Feng MODULE_LICENSE("GPL v2");
175