1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // MFD core driver for the Maxim MAX77843 |
4 | // |
5 | // Copyright (C) 2015 Samsung Electronics |
6 | // Author: Jaewon Kim <jaewon02.kim@samsung.com> |
7 | // Author: Beomho Seo <beomho.seo@samsung.com> |
8 | |
9 | #include <linux/err.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/mfd/core.h> |
14 | #include <linux/mfd/max77693-common.h> |
15 | #include <linux/mfd/max77843-private.h> |
16 | #include <linux/mod_devicetable.h> |
17 | #include <linux/platform_device.h> |
18 | |
19 | static const struct mfd_cell max77843_devs[] = { |
20 | { |
21 | .name = "max77843-muic" , |
22 | .of_compatible = "maxim,max77843-muic" , |
23 | }, { |
24 | .name = "max77843-regulator" , |
25 | .of_compatible = "maxim,max77843-regulator" , |
26 | }, { |
27 | .name = "max77843-charger" , |
28 | .of_compatible = "maxim,max77843-charger" |
29 | }, { |
30 | .name = "max77843-fuelgauge" , |
31 | .of_compatible = "maxim,max77843-fuelgauge" , |
32 | }, { |
33 | .name = "max77843-haptic" , |
34 | .of_compatible = "maxim,max77843-haptic" , |
35 | }, |
36 | }; |
37 | |
38 | static const struct regmap_config max77843_charger_regmap_config = { |
39 | .reg_bits = 8, |
40 | .val_bits = 8, |
41 | .max_register = MAX77843_CHG_REG_END, |
42 | }; |
43 | |
44 | static const struct regmap_config max77843_regmap_config = { |
45 | .reg_bits = 8, |
46 | .val_bits = 8, |
47 | .max_register = MAX77843_SYS_REG_END, |
48 | }; |
49 | |
50 | static const struct regmap_irq max77843_irqs[] = { |
51 | /* TOPSYS interrupts */ |
52 | { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, }, |
53 | { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, }, |
54 | { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, }, |
55 | { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, }, |
56 | }; |
57 | |
58 | static const struct regmap_irq_chip max77843_irq_chip = { |
59 | .name = "max77843" , |
60 | .status_base = MAX77843_SYS_REG_SYSINTSRC, |
61 | .mask_base = MAX77843_SYS_REG_SYSINTMASK, |
62 | .num_regs = 1, |
63 | .irqs = max77843_irqs, |
64 | .num_irqs = ARRAY_SIZE(max77843_irqs), |
65 | }; |
66 | |
67 | /* Charger and Charger regulator use same regmap. */ |
68 | static int max77843_chg_init(struct max77693_dev *max77843) |
69 | { |
70 | int ret; |
71 | |
72 | max77843->i2c_chg = i2c_new_dummy_device(adapter: max77843->i2c->adapter, I2C_ADDR_CHG); |
73 | if (IS_ERR(ptr: max77843->i2c_chg)) { |
74 | dev_err(&max77843->i2c->dev, |
75 | "Cannot allocate I2C device for Charger\n" ); |
76 | return PTR_ERR(ptr: max77843->i2c_chg); |
77 | } |
78 | i2c_set_clientdata(client: max77843->i2c_chg, data: max77843); |
79 | |
80 | max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg, |
81 | &max77843_charger_regmap_config); |
82 | if (IS_ERR(ptr: max77843->regmap_chg)) { |
83 | ret = PTR_ERR(ptr: max77843->regmap_chg); |
84 | goto err_chg_i2c; |
85 | } |
86 | |
87 | return 0; |
88 | |
89 | err_chg_i2c: |
90 | i2c_unregister_device(client: max77843->i2c_chg); |
91 | |
92 | return ret; |
93 | } |
94 | |
95 | static int max77843_probe(struct i2c_client *i2c) |
96 | { |
97 | const struct i2c_device_id *id = i2c_client_get_device_id(client: i2c); |
98 | struct max77693_dev *max77843; |
99 | unsigned int reg_data; |
100 | int ret; |
101 | |
102 | max77843 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*max77843), GFP_KERNEL); |
103 | if (!max77843) |
104 | return -ENOMEM; |
105 | |
106 | i2c_set_clientdata(client: i2c, data: max77843); |
107 | max77843->dev = &i2c->dev; |
108 | max77843->i2c = i2c; |
109 | max77843->irq = i2c->irq; |
110 | max77843->type = id->driver_data; |
111 | |
112 | max77843->regmap = devm_regmap_init_i2c(i2c, |
113 | &max77843_regmap_config); |
114 | if (IS_ERR(ptr: max77843->regmap)) { |
115 | dev_err(&i2c->dev, "Failed to allocate topsys register map\n" ); |
116 | return PTR_ERR(ptr: max77843->regmap); |
117 | } |
118 | |
119 | ret = regmap_add_irq_chip(map: max77843->regmap, irq: max77843->irq, |
120 | IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, |
121 | irq_base: 0, chip: &max77843_irq_chip, data: &max77843->irq_data_topsys); |
122 | if (ret) { |
123 | dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n" ); |
124 | return ret; |
125 | } |
126 | |
127 | ret = regmap_read(map: max77843->regmap, |
128 | reg: MAX77843_SYS_REG_PMICID, val: ®_data); |
129 | if (ret < 0) { |
130 | dev_err(&i2c->dev, "Failed to read PMIC ID\n" ); |
131 | goto err_pmic_id; |
132 | } |
133 | dev_info(&i2c->dev, "device ID: 0x%x\n" , reg_data); |
134 | |
135 | ret = max77843_chg_init(max77843); |
136 | if (ret) { |
137 | dev_err(&i2c->dev, "Failed to init Charger\n" ); |
138 | goto err_pmic_id; |
139 | } |
140 | |
141 | ret = regmap_update_bits(map: max77843->regmap, |
142 | reg: MAX77843_SYS_REG_INTSRCMASK, |
143 | MAX77843_INTSRC_MASK_MASK, |
144 | val: (unsigned int)~MAX77843_INTSRC_MASK_MASK); |
145 | if (ret < 0) { |
146 | dev_err(&i2c->dev, "Failed to unmask interrupt source\n" ); |
147 | goto err_pmic_id; |
148 | } |
149 | |
150 | ret = mfd_add_devices(parent: max77843->dev, id: -1, cells: max77843_devs, |
151 | ARRAY_SIZE(max77843_devs), NULL, irq_base: 0, NULL); |
152 | if (ret < 0) { |
153 | dev_err(&i2c->dev, "Failed to add mfd device\n" ); |
154 | goto err_pmic_id; |
155 | } |
156 | |
157 | device_init_wakeup(dev: max77843->dev, enable: true); |
158 | |
159 | return 0; |
160 | |
161 | err_pmic_id: |
162 | regmap_del_irq_chip(irq: max77843->irq, data: max77843->irq_data_topsys); |
163 | |
164 | return ret; |
165 | } |
166 | |
167 | static const struct of_device_id max77843_dt_match[] = { |
168 | { .compatible = "maxim,max77843" , }, |
169 | { }, |
170 | }; |
171 | |
172 | static const struct i2c_device_id max77843_id[] = { |
173 | { "max77843" , TYPE_MAX77843, }, |
174 | { }, |
175 | }; |
176 | |
177 | static int __maybe_unused max77843_suspend(struct device *dev) |
178 | { |
179 | struct i2c_client *i2c = to_i2c_client(dev); |
180 | struct max77693_dev *max77843 = i2c_get_clientdata(client: i2c); |
181 | |
182 | disable_irq(irq: max77843->irq); |
183 | if (device_may_wakeup(dev)) |
184 | enable_irq_wake(irq: max77843->irq); |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | static int __maybe_unused max77843_resume(struct device *dev) |
190 | { |
191 | struct i2c_client *i2c = to_i2c_client(dev); |
192 | struct max77693_dev *max77843 = i2c_get_clientdata(client: i2c); |
193 | |
194 | if (device_may_wakeup(dev)) |
195 | disable_irq_wake(irq: max77843->irq); |
196 | enable_irq(irq: max77843->irq); |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume); |
202 | |
203 | static struct i2c_driver max77843_i2c_driver = { |
204 | .driver = { |
205 | .name = "max77843" , |
206 | .pm = &max77843_pm, |
207 | .of_match_table = max77843_dt_match, |
208 | .suppress_bind_attrs = true, |
209 | }, |
210 | .probe = max77843_probe, |
211 | .id_table = max77843_id, |
212 | }; |
213 | |
214 | static int __init max77843_i2c_init(void) |
215 | { |
216 | return i2c_add_driver(&max77843_i2c_driver); |
217 | } |
218 | subsys_initcall(max77843_i2c_init); |
219 | |