1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
4   * LCD Backlight: drivers/video/backlight/adp5520_bl
5   * LEDs		: drivers/led/leds-adp5520
6   * GPIO		: drivers/gpio/adp5520-gpio (ADP5520 only)
7   * Keys		: drivers/input/keyboard/adp5520-keys (ADP5520 only)
8   *
9   * Copyright 2009 Analog Devices Inc.
10   *
11   * Author: Michael Hennerich <michael.hennerich@analog.com>
12   *
13   * Derived from da903x:
14   * Copyright (C) 2008 Compulab, Ltd.
15   *	Mike Rapoport <mike@compulab.co.il>
16   *
17   * Copyright (C) 2006-2008 Marvell International Ltd.
18   *	Eric Miao <eric.miao@marvell.com>
19   */
20  
21  #include <linux/kernel.h>
22  #include <linux/init.h>
23  #include <linux/platform_device.h>
24  #include <linux/slab.h>
25  #include <linux/interrupt.h>
26  #include <linux/irq.h>
27  #include <linux/err.h>
28  #include <linux/i2c.h>
29  
30  #include <linux/mfd/adp5520.h>
31  
32  struct adp5520_chip {
33  	struct i2c_client *client;
34  	struct device *dev;
35  	struct mutex lock;
36  	struct blocking_notifier_head notifier_list;
37  	int irq;
38  	unsigned long id;
39  	uint8_t mode;
40  };
41  
__adp5520_read(struct i2c_client * client,int reg,uint8_t * val)42  static int __adp5520_read(struct i2c_client *client,
43  				int reg, uint8_t *val)
44  {
45  	int ret;
46  
47  	ret = i2c_smbus_read_byte_data(client, reg);
48  	if (ret < 0) {
49  		dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
50  		return ret;
51  	}
52  
53  	*val = (uint8_t)ret;
54  	return 0;
55  }
56  
__adp5520_write(struct i2c_client * client,int reg,uint8_t val)57  static int __adp5520_write(struct i2c_client *client,
58  				 int reg, uint8_t val)
59  {
60  	int ret;
61  
62  	ret = i2c_smbus_write_byte_data(client, reg, val);
63  	if (ret < 0) {
64  		dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
65  				val, reg);
66  		return ret;
67  	}
68  	return 0;
69  }
70  
__adp5520_ack_bits(struct i2c_client * client,int reg,uint8_t bit_mask)71  static int __adp5520_ack_bits(struct i2c_client *client, int reg,
72  			      uint8_t bit_mask)
73  {
74  	struct adp5520_chip *chip = i2c_get_clientdata(client);
75  	uint8_t reg_val;
76  	int ret;
77  
78  	mutex_lock(&chip->lock);
79  
80  	ret = __adp5520_read(client, reg, &reg_val);
81  
82  	if (!ret) {
83  		reg_val |= bit_mask;
84  		ret = __adp5520_write(client, reg, reg_val);
85  	}
86  
87  	mutex_unlock(&chip->lock);
88  	return ret;
89  }
90  
adp5520_write(struct device * dev,int reg,uint8_t val)91  int adp5520_write(struct device *dev, int reg, uint8_t val)
92  {
93  	return __adp5520_write(to_i2c_client(dev), reg, val);
94  }
95  EXPORT_SYMBOL_GPL(adp5520_write);
96  
adp5520_read(struct device * dev,int reg,uint8_t * val)97  int adp5520_read(struct device *dev, int reg, uint8_t *val)
98  {
99  	return __adp5520_read(to_i2c_client(dev), reg, val);
100  }
101  EXPORT_SYMBOL_GPL(adp5520_read);
102  
adp5520_set_bits(struct device * dev,int reg,uint8_t bit_mask)103  int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
104  {
105  	struct adp5520_chip *chip = dev_get_drvdata(dev);
106  	uint8_t reg_val;
107  	int ret;
108  
109  	mutex_lock(&chip->lock);
110  
111  	ret = __adp5520_read(chip->client, reg, &reg_val);
112  
113  	if (!ret && ((reg_val & bit_mask) != bit_mask)) {
114  		reg_val |= bit_mask;
115  		ret = __adp5520_write(chip->client, reg, reg_val);
116  	}
117  
118  	mutex_unlock(&chip->lock);
119  	return ret;
120  }
121  EXPORT_SYMBOL_GPL(adp5520_set_bits);
122  
adp5520_clr_bits(struct device * dev,int reg,uint8_t bit_mask)123  int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
124  {
125  	struct adp5520_chip *chip = dev_get_drvdata(dev);
126  	uint8_t reg_val;
127  	int ret;
128  
129  	mutex_lock(&chip->lock);
130  
131  	ret = __adp5520_read(chip->client, reg, &reg_val);
132  
133  	if (!ret && (reg_val & bit_mask)) {
134  		reg_val &= ~bit_mask;
135  		ret = __adp5520_write(chip->client, reg, reg_val);
136  	}
137  
138  	mutex_unlock(&chip->lock);
139  	return ret;
140  }
141  EXPORT_SYMBOL_GPL(adp5520_clr_bits);
142  
adp5520_register_notifier(struct device * dev,struct notifier_block * nb,unsigned int events)143  int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
144  				unsigned int events)
145  {
146  	struct adp5520_chip *chip = dev_get_drvdata(dev);
147  
148  	if (chip->irq) {
149  		adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
150  			events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
151  			ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
152  
153  		return blocking_notifier_chain_register(&chip->notifier_list,
154  			 nb);
155  	}
156  
157  	return -ENODEV;
158  }
159  EXPORT_SYMBOL_GPL(adp5520_register_notifier);
160  
adp5520_unregister_notifier(struct device * dev,struct notifier_block * nb,unsigned int events)161  int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
162  				unsigned int events)
163  {
164  	struct adp5520_chip *chip = dev_get_drvdata(dev);
165  
166  	adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
167  		events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
168  		ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
169  
170  	return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
171  }
172  EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
173  
adp5520_irq_thread(int irq,void * data)174  static irqreturn_t adp5520_irq_thread(int irq, void *data)
175  {
176  	struct adp5520_chip *chip = data;
177  	unsigned int events;
178  	uint8_t reg_val;
179  	int ret;
180  
181  	ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, &reg_val);
182  	if (ret)
183  		goto out;
184  
185  	events =  reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT |
186  		ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT);
187  
188  	blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
189  	/* ACK, Sticky bits are W1C */
190  	__adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events);
191  
192  out:
193  	return IRQ_HANDLED;
194  }
195  
__remove_subdev(struct device * dev,void * unused)196  static int __remove_subdev(struct device *dev, void *unused)
197  {
198  	platform_device_unregister(to_platform_device(dev));
199  	return 0;
200  }
201  
adp5520_remove_subdevs(struct adp5520_chip * chip)202  static int adp5520_remove_subdevs(struct adp5520_chip *chip)
203  {
204  	return device_for_each_child(chip->dev, NULL, __remove_subdev);
205  }
206  
adp5520_probe(struct i2c_client * client)207  static int adp5520_probe(struct i2c_client *client)
208  {
209  	const struct i2c_device_id *id = i2c_client_get_device_id(client);
210  	struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev);
211  	struct platform_device *pdev;
212  	struct adp5520_chip *chip;
213  	int ret;
214  
215  	if (!i2c_check_functionality(client->adapter,
216  					I2C_FUNC_SMBUS_BYTE_DATA)) {
217  		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
218  		return -EIO;
219  	}
220  
221  	if (pdata == NULL) {
222  		dev_err(&client->dev, "missing platform data\n");
223  		return -ENODEV;
224  	}
225  
226  	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
227  	if (!chip)
228  		return -ENOMEM;
229  
230  	i2c_set_clientdata(client, chip);
231  	chip->client = client;
232  
233  	chip->dev = &client->dev;
234  	chip->irq = client->irq;
235  	chip->id = id->driver_data;
236  	mutex_init(&chip->lock);
237  
238  	if (chip->irq) {
239  		BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
240  
241  		ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread,
242  				IRQF_TRIGGER_LOW | IRQF_ONESHOT,
243  				"adp5520", chip);
244  		if (ret) {
245  			dev_err(&client->dev, "failed to request irq %d\n",
246  					chip->irq);
247  			return ret;
248  		}
249  	}
250  
251  	ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
252  	if (ret) {
253  		dev_err(&client->dev, "failed to write\n");
254  		goto out_free_irq;
255  	}
256  
257  	if (pdata->keys) {
258  		pdev = platform_device_register_data(chip->dev, "adp5520-keys",
259  				chip->id, pdata->keys, sizeof(*pdata->keys));
260  		if (IS_ERR(pdev)) {
261  			ret = PTR_ERR(pdev);
262  			goto out_remove_subdevs;
263  		}
264  	}
265  
266  	if (pdata->gpio) {
267  		pdev = platform_device_register_data(chip->dev, "adp5520-gpio",
268  				chip->id, pdata->gpio, sizeof(*pdata->gpio));
269  		if (IS_ERR(pdev)) {
270  			ret = PTR_ERR(pdev);
271  			goto out_remove_subdevs;
272  		}
273  	}
274  
275  	if (pdata->leds) {
276  		pdev = platform_device_register_data(chip->dev, "adp5520-led",
277  				chip->id, pdata->leds, sizeof(*pdata->leds));
278  		if (IS_ERR(pdev)) {
279  			ret = PTR_ERR(pdev);
280  			goto out_remove_subdevs;
281  		}
282  	}
283  
284  	if (pdata->backlight) {
285  		pdev = platform_device_register_data(chip->dev,
286  						"adp5520-backlight",
287  						chip->id,
288  						pdata->backlight,
289  						sizeof(*pdata->backlight));
290  		if (IS_ERR(pdev)) {
291  			ret = PTR_ERR(pdev);
292  			goto out_remove_subdevs;
293  		}
294  	}
295  
296  	return 0;
297  
298  out_remove_subdevs:
299  	adp5520_remove_subdevs(chip);
300  
301  out_free_irq:
302  	if (chip->irq)
303  		free_irq(chip->irq, chip);
304  
305  	return ret;
306  }
307  
adp5520_suspend(struct device * dev)308  static int adp5520_suspend(struct device *dev)
309  {
310  	struct i2c_client *client = to_i2c_client(dev);
311  	struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
312  
313  	adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode);
314  	/* All other bits are W1C */
315  	chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY;
316  	adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
317  	return 0;
318  }
319  
adp5520_resume(struct device * dev)320  static int adp5520_resume(struct device *dev)
321  {
322  	struct i2c_client *client = to_i2c_client(dev);
323  	struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
324  
325  	adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode);
326  	return 0;
327  }
328  
329  static DEFINE_SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume);
330  
331  static const struct i2c_device_id adp5520_id[] = {
332  	{ "pmic-adp5520", ID_ADP5520 },
333  	{ "pmic-adp5501", ID_ADP5501 },
334  	{ }
335  };
336  
337  static struct i2c_driver adp5520_driver = {
338  	.driver = {
339  		.name			= "adp5520",
340  		.pm			= pm_sleep_ptr(&adp5520_pm),
341  		.suppress_bind_attrs	= true,
342  	},
343  	.probe		= adp5520_probe,
344  	.id_table	= adp5520_id,
345  };
346  builtin_i2c_driver(adp5520_driver);
347