xref: /openbmc/linux/drivers/mfd/hi655x-pmic.c (revision dc0c386e)
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