xref: /openbmc/linux/drivers/mfd/da903x.c (revision 9816d859)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
226b8f5e1SEric Miao /*
326b8f5e1SEric Miao  * Base driver for Dialog Semiconductor DA9030/DA9034
426b8f5e1SEric Miao  *
526b8f5e1SEric Miao  * Copyright (C) 2008 Compulab, Ltd.
626b8f5e1SEric Miao  *	Mike Rapoport <mike@compulab.co.il>
726b8f5e1SEric Miao  *
826b8f5e1SEric Miao  * Copyright (C) 2006-2008 Marvell International Ltd.
926b8f5e1SEric Miao  *	Eric Miao <eric.miao@marvell.com>
1026b8f5e1SEric Miao  */
1126b8f5e1SEric Miao 
1226b8f5e1SEric Miao #include <linux/kernel.h>
1326b8f5e1SEric Miao #include <linux/module.h>
1426b8f5e1SEric Miao #include <linux/interrupt.h>
1526b8f5e1SEric Miao #include <linux/platform_device.h>
1626b8f5e1SEric Miao #include <linux/i2c.h>
1726b8f5e1SEric Miao #include <linux/mfd/da903x.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1926b8f5e1SEric Miao 
2026b8f5e1SEric Miao #define DA9030_CHIP_ID		0x00
2126b8f5e1SEric Miao #define DA9030_EVENT_A		0x01
2226b8f5e1SEric Miao #define DA9030_EVENT_B		0x02
2326b8f5e1SEric Miao #define DA9030_EVENT_C		0x03
2426b8f5e1SEric Miao #define DA9030_STATUS		0x04
2526b8f5e1SEric Miao #define DA9030_IRQ_MASK_A	0x05
2626b8f5e1SEric Miao #define DA9030_IRQ_MASK_B	0x06
2726b8f5e1SEric Miao #define DA9030_IRQ_MASK_C	0x07
2826b8f5e1SEric Miao #define DA9030_SYS_CTRL_A	0x08
2926b8f5e1SEric Miao #define DA9030_SYS_CTRL_B	0x09
3026b8f5e1SEric Miao #define DA9030_FAULT_LOG	0x0a
3126b8f5e1SEric Miao 
3226b8f5e1SEric Miao #define DA9034_CHIP_ID		0x00
3326b8f5e1SEric Miao #define DA9034_EVENT_A		0x01
3426b8f5e1SEric Miao #define DA9034_EVENT_B		0x02
3526b8f5e1SEric Miao #define DA9034_EVENT_C		0x03
3626b8f5e1SEric Miao #define DA9034_EVENT_D		0x04
3726b8f5e1SEric Miao #define DA9034_STATUS_A		0x05
3826b8f5e1SEric Miao #define DA9034_STATUS_B		0x06
3926b8f5e1SEric Miao #define DA9034_IRQ_MASK_A	0x07
4026b8f5e1SEric Miao #define DA9034_IRQ_MASK_B	0x08
4126b8f5e1SEric Miao #define DA9034_IRQ_MASK_C	0x09
4226b8f5e1SEric Miao #define DA9034_IRQ_MASK_D	0x0a
4326b8f5e1SEric Miao #define DA9034_SYS_CTRL_A	0x0b
4426b8f5e1SEric Miao #define DA9034_SYS_CTRL_B	0x0c
4526b8f5e1SEric Miao #define DA9034_FAULT_LOG	0x0d
4626b8f5e1SEric Miao 
4726b8f5e1SEric Miao struct da903x_chip;
4826b8f5e1SEric Miao 
4926b8f5e1SEric Miao struct da903x_chip_ops {
5026b8f5e1SEric Miao 	int	(*init_chip)(struct da903x_chip *);
5126b8f5e1SEric Miao 	int	(*unmask_events)(struct da903x_chip *, unsigned int events);
5226b8f5e1SEric Miao 	int	(*mask_events)(struct da903x_chip *, unsigned int events);
5326b8f5e1SEric Miao 	int	(*read_events)(struct da903x_chip *, unsigned int *events);
5426b8f5e1SEric Miao 	int	(*read_status)(struct da903x_chip *, unsigned int *status);
5526b8f5e1SEric Miao };
5626b8f5e1SEric Miao 
5726b8f5e1SEric Miao struct da903x_chip {
5826b8f5e1SEric Miao 	struct i2c_client	*client;
5926b8f5e1SEric Miao 	struct device		*dev;
60f83e7d81SJulia Lawall 	const struct da903x_chip_ops *ops;
6126b8f5e1SEric Miao 
6226b8f5e1SEric Miao 	int			type;
6326b8f5e1SEric Miao 	uint32_t		events_mask;
6426b8f5e1SEric Miao 
6526b8f5e1SEric Miao 	struct mutex		lock;
6626b8f5e1SEric Miao 	struct work_struct	irq_work;
6726b8f5e1SEric Miao 
6826b8f5e1SEric Miao 	struct blocking_notifier_head notifier_list;
6926b8f5e1SEric Miao };
7026b8f5e1SEric Miao 
__da903x_read(struct i2c_client * client,int reg,uint8_t * val)7126b8f5e1SEric Miao static inline int __da903x_read(struct i2c_client *client,
7226b8f5e1SEric Miao 				int reg, uint8_t *val)
7326b8f5e1SEric Miao {
7426b8f5e1SEric Miao 	int ret;
7526b8f5e1SEric Miao 
7626b8f5e1SEric Miao 	ret = i2c_smbus_read_byte_data(client, reg);
7726b8f5e1SEric Miao 	if (ret < 0) {
7826b8f5e1SEric Miao 		dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
7926b8f5e1SEric Miao 		return ret;
8026b8f5e1SEric Miao 	}
8126b8f5e1SEric Miao 
8226b8f5e1SEric Miao 	*val = (uint8_t)ret;
8326b8f5e1SEric Miao 	return 0;
8426b8f5e1SEric Miao }
8526b8f5e1SEric Miao 
__da903x_reads(struct i2c_client * client,int reg,int len,uint8_t * val)8626b8f5e1SEric Miao static inline int __da903x_reads(struct i2c_client *client, int reg,
8726b8f5e1SEric Miao 				 int len, uint8_t *val)
8826b8f5e1SEric Miao {
8926b8f5e1SEric Miao 	int ret;
9026b8f5e1SEric Miao 
9126b8f5e1SEric Miao 	ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
9226b8f5e1SEric Miao 	if (ret < 0) {
9326b8f5e1SEric Miao 		dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
9426b8f5e1SEric Miao 		return ret;
9526b8f5e1SEric Miao 	}
9626b8f5e1SEric Miao 	return 0;
9726b8f5e1SEric Miao }
9826b8f5e1SEric Miao 
__da903x_write(struct i2c_client * client,int reg,uint8_t val)9926b8f5e1SEric Miao static inline int __da903x_write(struct i2c_client *client,
10026b8f5e1SEric Miao 				 int reg, uint8_t val)
10126b8f5e1SEric Miao {
10226b8f5e1SEric Miao 	int ret;
10326b8f5e1SEric Miao 
10426b8f5e1SEric Miao 	ret = i2c_smbus_write_byte_data(client, reg, val);
10526b8f5e1SEric Miao 	if (ret < 0) {
10626b8f5e1SEric Miao 		dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
10726b8f5e1SEric Miao 				val, reg);
10826b8f5e1SEric Miao 		return ret;
10926b8f5e1SEric Miao 	}
11026b8f5e1SEric Miao 	return 0;
11126b8f5e1SEric Miao }
11226b8f5e1SEric Miao 
__da903x_writes(struct i2c_client * client,int reg,int len,uint8_t * val)11326b8f5e1SEric Miao static inline int __da903x_writes(struct i2c_client *client, int reg,
11426b8f5e1SEric Miao 				  int len, uint8_t *val)
11526b8f5e1SEric Miao {
11626b8f5e1SEric Miao 	int ret;
11726b8f5e1SEric Miao 
11826b8f5e1SEric Miao 	ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
11926b8f5e1SEric Miao 	if (ret < 0) {
12026b8f5e1SEric Miao 		dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
12126b8f5e1SEric Miao 		return ret;
12226b8f5e1SEric Miao 	}
12326b8f5e1SEric Miao 	return 0;
12426b8f5e1SEric Miao }
12526b8f5e1SEric Miao 
da903x_register_notifier(struct device * dev,struct notifier_block * nb,unsigned int events)12626b8f5e1SEric Miao int da903x_register_notifier(struct device *dev, struct notifier_block *nb,
12726b8f5e1SEric Miao 				unsigned int events)
12826b8f5e1SEric Miao {
12926b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
13026b8f5e1SEric Miao 
13126b8f5e1SEric Miao 	chip->ops->unmask_events(chip, events);
13226b8f5e1SEric Miao 	return blocking_notifier_chain_register(&chip->notifier_list, nb);
13326b8f5e1SEric Miao }
13426b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_register_notifier);
13526b8f5e1SEric Miao 
da903x_unregister_notifier(struct device * dev,struct notifier_block * nb,unsigned int events)13626b8f5e1SEric Miao int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb,
13726b8f5e1SEric Miao 				unsigned int events)
13826b8f5e1SEric Miao {
13926b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
14026b8f5e1SEric Miao 
14126b8f5e1SEric Miao 	chip->ops->mask_events(chip, events);
14226b8f5e1SEric Miao 	return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
14326b8f5e1SEric Miao }
14426b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_unregister_notifier);
14526b8f5e1SEric Miao 
da903x_write(struct device * dev,int reg,uint8_t val)14626b8f5e1SEric Miao int da903x_write(struct device *dev, int reg, uint8_t val)
14726b8f5e1SEric Miao {
14826b8f5e1SEric Miao 	return __da903x_write(to_i2c_client(dev), reg, val);
14926b8f5e1SEric Miao }
15026b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_write);
15126b8f5e1SEric Miao 
da903x_writes(struct device * dev,int reg,int len,uint8_t * val)152856f6fd1SMike Rapoport int da903x_writes(struct device *dev, int reg, int len, uint8_t *val)
153856f6fd1SMike Rapoport {
154856f6fd1SMike Rapoport 	return __da903x_writes(to_i2c_client(dev), reg, len, val);
155856f6fd1SMike Rapoport }
156856f6fd1SMike Rapoport EXPORT_SYMBOL_GPL(da903x_writes);
157856f6fd1SMike Rapoport 
da903x_read(struct device * dev,int reg,uint8_t * val)15826b8f5e1SEric Miao int da903x_read(struct device *dev, int reg, uint8_t *val)
15926b8f5e1SEric Miao {
16026b8f5e1SEric Miao 	return __da903x_read(to_i2c_client(dev), reg, val);
16126b8f5e1SEric Miao }
16226b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_read);
16326b8f5e1SEric Miao 
da903x_reads(struct device * dev,int reg,int len,uint8_t * val)164856f6fd1SMike Rapoport int da903x_reads(struct device *dev, int reg, int len, uint8_t *val)
165856f6fd1SMike Rapoport {
166856f6fd1SMike Rapoport 	return __da903x_reads(to_i2c_client(dev), reg, len, val);
167856f6fd1SMike Rapoport }
168856f6fd1SMike Rapoport EXPORT_SYMBOL_GPL(da903x_reads);
169856f6fd1SMike Rapoport 
da903x_set_bits(struct device * dev,int reg,uint8_t bit_mask)17026b8f5e1SEric Miao int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
17126b8f5e1SEric Miao {
17226b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
17326b8f5e1SEric Miao 	uint8_t reg_val;
17426b8f5e1SEric Miao 	int ret = 0;
17526b8f5e1SEric Miao 
17626b8f5e1SEric Miao 	mutex_lock(&chip->lock);
17726b8f5e1SEric Miao 
17826b8f5e1SEric Miao 	ret = __da903x_read(chip->client, reg, &reg_val);
17926b8f5e1SEric Miao 	if (ret)
18026b8f5e1SEric Miao 		goto out;
18126b8f5e1SEric Miao 
182af65e6ceSAxel Lin 	if ((reg_val & bit_mask) != bit_mask) {
18326b8f5e1SEric Miao 		reg_val |= bit_mask;
18426b8f5e1SEric Miao 		ret = __da903x_write(chip->client, reg, reg_val);
18526b8f5e1SEric Miao 	}
18626b8f5e1SEric Miao out:
18726b8f5e1SEric Miao 	mutex_unlock(&chip->lock);
18826b8f5e1SEric Miao 	return ret;
18926b8f5e1SEric Miao }
19026b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_set_bits);
19126b8f5e1SEric Miao 
da903x_clr_bits(struct device * dev,int reg,uint8_t bit_mask)19226b8f5e1SEric Miao int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
19326b8f5e1SEric Miao {
19426b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
19526b8f5e1SEric Miao 	uint8_t reg_val;
19626b8f5e1SEric Miao 	int ret = 0;
19726b8f5e1SEric Miao 
19826b8f5e1SEric Miao 	mutex_lock(&chip->lock);
19926b8f5e1SEric Miao 
20026b8f5e1SEric Miao 	ret = __da903x_read(chip->client, reg, &reg_val);
20126b8f5e1SEric Miao 	if (ret)
20226b8f5e1SEric Miao 		goto out;
20326b8f5e1SEric Miao 
20426b8f5e1SEric Miao 	if (reg_val & bit_mask) {
20526b8f5e1SEric Miao 		reg_val &= ~bit_mask;
20626b8f5e1SEric Miao 		ret = __da903x_write(chip->client, reg, reg_val);
20726b8f5e1SEric Miao 	}
20826b8f5e1SEric Miao out:
20926b8f5e1SEric Miao 	mutex_unlock(&chip->lock);
21026b8f5e1SEric Miao 	return ret;
21126b8f5e1SEric Miao }
21226b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_clr_bits);
21326b8f5e1SEric Miao 
da903x_update(struct device * dev,int reg,uint8_t val,uint8_t mask)21426b8f5e1SEric Miao int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
21526b8f5e1SEric Miao {
21626b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
21726b8f5e1SEric Miao 	uint8_t reg_val;
21826b8f5e1SEric Miao 	int ret = 0;
21926b8f5e1SEric Miao 
22026b8f5e1SEric Miao 	mutex_lock(&chip->lock);
22126b8f5e1SEric Miao 
22226b8f5e1SEric Miao 	ret = __da903x_read(chip->client, reg, &reg_val);
22326b8f5e1SEric Miao 	if (ret)
22426b8f5e1SEric Miao 		goto out;
22526b8f5e1SEric Miao 
22626b8f5e1SEric Miao 	if ((reg_val & mask) != val) {
22726b8f5e1SEric Miao 		reg_val = (reg_val & ~mask) | val;
22826b8f5e1SEric Miao 		ret = __da903x_write(chip->client, reg, reg_val);
22926b8f5e1SEric Miao 	}
23026b8f5e1SEric Miao out:
23126b8f5e1SEric Miao 	mutex_unlock(&chip->lock);
23226b8f5e1SEric Miao 	return ret;
23326b8f5e1SEric Miao }
23426b8f5e1SEric Miao EXPORT_SYMBOL_GPL(da903x_update);
23526b8f5e1SEric Miao 
da903x_query_status(struct device * dev,unsigned int sbits)23626b8f5e1SEric Miao int da903x_query_status(struct device *dev, unsigned int sbits)
23726b8f5e1SEric Miao {
23826b8f5e1SEric Miao 	struct da903x_chip *chip = dev_get_drvdata(dev);
23926b8f5e1SEric Miao 	unsigned int status = 0;
24026b8f5e1SEric Miao 
24126b8f5e1SEric Miao 	chip->ops->read_status(chip, &status);
24226b8f5e1SEric Miao 	return ((status & sbits) == sbits);
24326b8f5e1SEric Miao }
24426b8f5e1SEric Miao EXPORT_SYMBOL(da903x_query_status);
24526b8f5e1SEric Miao 
da9030_init_chip(struct da903x_chip * chip)246f791be49SBill Pemberton static int da9030_init_chip(struct da903x_chip *chip)
24726b8f5e1SEric Miao {
24826b8f5e1SEric Miao 	uint8_t chip_id;
24926b8f5e1SEric Miao 	int err;
25026b8f5e1SEric Miao 
25126b8f5e1SEric Miao 	err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id);
25226b8f5e1SEric Miao 	if (err)
25326b8f5e1SEric Miao 		return err;
25426b8f5e1SEric Miao 
25526b8f5e1SEric Miao 	err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8);
25626b8f5e1SEric Miao 	if (err)
25726b8f5e1SEric Miao 		return err;
25826b8f5e1SEric Miao 
25926b8f5e1SEric Miao 	dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id);
26026b8f5e1SEric Miao 	return 0;
26126b8f5e1SEric Miao }
26226b8f5e1SEric Miao 
da9030_unmask_events(struct da903x_chip * chip,unsigned int events)26326b8f5e1SEric Miao static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events)
26426b8f5e1SEric Miao {
26526b8f5e1SEric Miao 	uint8_t v[3];
26626b8f5e1SEric Miao 
26726b8f5e1SEric Miao 	chip->events_mask &= ~events;
26826b8f5e1SEric Miao 
26926b8f5e1SEric Miao 	v[0] = (chip->events_mask & 0xff);
27026b8f5e1SEric Miao 	v[1] = (chip->events_mask >> 8) & 0xff;
27126b8f5e1SEric Miao 	v[2] = (chip->events_mask >> 16) & 0xff;
27226b8f5e1SEric Miao 
27326b8f5e1SEric Miao 	return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
27426b8f5e1SEric Miao }
27526b8f5e1SEric Miao 
da9030_mask_events(struct da903x_chip * chip,unsigned int events)27626b8f5e1SEric Miao static int da9030_mask_events(struct da903x_chip *chip, unsigned int events)
27726b8f5e1SEric Miao {
27826b8f5e1SEric Miao 	uint8_t v[3];
27926b8f5e1SEric Miao 
280b1ccbdc4SMike Rapoport 	chip->events_mask |= events;
28126b8f5e1SEric Miao 
28226b8f5e1SEric Miao 	v[0] = (chip->events_mask & 0xff);
28326b8f5e1SEric Miao 	v[1] = (chip->events_mask >> 8) & 0xff;
28426b8f5e1SEric Miao 	v[2] = (chip->events_mask >> 16) & 0xff;
28526b8f5e1SEric Miao 
28626b8f5e1SEric Miao 	return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
28726b8f5e1SEric Miao }
28826b8f5e1SEric Miao 
da9030_read_events(struct da903x_chip * chip,unsigned int * events)28926b8f5e1SEric Miao static int da9030_read_events(struct da903x_chip *chip, unsigned int *events)
29026b8f5e1SEric Miao {
29126b8f5e1SEric Miao 	uint8_t v[3] = {0, 0, 0};
29226b8f5e1SEric Miao 	int ret;
29326b8f5e1SEric Miao 
29426b8f5e1SEric Miao 	ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v);
29526b8f5e1SEric Miao 	if (ret < 0)
29626b8f5e1SEric Miao 		return ret;
29726b8f5e1SEric Miao 
29826b8f5e1SEric Miao 	*events = (v[2] << 16) | (v[1] << 8) | v[0];
29926b8f5e1SEric Miao 	return 0;
30026b8f5e1SEric Miao }
30126b8f5e1SEric Miao 
da9030_read_status(struct da903x_chip * chip,unsigned int * status)30226b8f5e1SEric Miao static int da9030_read_status(struct da903x_chip *chip, unsigned int *status)
30326b8f5e1SEric Miao {
30426b8f5e1SEric Miao 	return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status);
30526b8f5e1SEric Miao }
30626b8f5e1SEric Miao 
da9034_init_chip(struct da903x_chip * chip)30726b8f5e1SEric Miao static int da9034_init_chip(struct da903x_chip *chip)
30826b8f5e1SEric Miao {
30926b8f5e1SEric Miao 	uint8_t chip_id;
31026b8f5e1SEric Miao 	int err;
31126b8f5e1SEric Miao 
31226b8f5e1SEric Miao 	err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id);
31326b8f5e1SEric Miao 	if (err)
31426b8f5e1SEric Miao 		return err;
31526b8f5e1SEric Miao 
31626b8f5e1SEric Miao 	err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8);
31726b8f5e1SEric Miao 	if (err)
31826b8f5e1SEric Miao 		return err;
31926b8f5e1SEric Miao 
32026b8f5e1SEric Miao 	/* avoid SRAM power off during sleep*/
32126b8f5e1SEric Miao 	__da903x_write(chip->client, 0x10, 0x07);
32226b8f5e1SEric Miao 	__da903x_write(chip->client, 0x11, 0xff);
32326b8f5e1SEric Miao 	__da903x_write(chip->client, 0x12, 0xff);
32426b8f5e1SEric Miao 
32526b8f5e1SEric Miao 	/* Enable the ONKEY power down functionality */
32626b8f5e1SEric Miao 	__da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20);
32726b8f5e1SEric Miao 	__da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60);
32826b8f5e1SEric Miao 
32926b8f5e1SEric Miao 	/* workaround to make LEDs work */
33026b8f5e1SEric Miao 	__da903x_write(chip->client, 0x90, 0x01);
33126b8f5e1SEric Miao 	__da903x_write(chip->client, 0xB0, 0x08);
33226b8f5e1SEric Miao 
33326b8f5e1SEric Miao 	/* make ADTV1 and SDTV1 effective */
33426b8f5e1SEric Miao 	__da903x_write(chip->client, 0x20, 0x00);
33526b8f5e1SEric Miao 
33626b8f5e1SEric Miao 	dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id);
33726b8f5e1SEric Miao 	return 0;
33826b8f5e1SEric Miao }
33926b8f5e1SEric Miao 
da9034_unmask_events(struct da903x_chip * chip,unsigned int events)34026b8f5e1SEric Miao static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events)
34126b8f5e1SEric Miao {
34226b8f5e1SEric Miao 	uint8_t v[4];
34326b8f5e1SEric Miao 
34426b8f5e1SEric Miao 	chip->events_mask &= ~events;
34526b8f5e1SEric Miao 
34626b8f5e1SEric Miao 	v[0] = (chip->events_mask & 0xff);
34726b8f5e1SEric Miao 	v[1] = (chip->events_mask >> 8) & 0xff;
34826b8f5e1SEric Miao 	v[2] = (chip->events_mask >> 16) & 0xff;
34926b8f5e1SEric Miao 	v[3] = (chip->events_mask >> 24) & 0xff;
35026b8f5e1SEric Miao 
35126b8f5e1SEric Miao 	return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
35226b8f5e1SEric Miao }
35326b8f5e1SEric Miao 
da9034_mask_events(struct da903x_chip * chip,unsigned int events)35426b8f5e1SEric Miao static int da9034_mask_events(struct da903x_chip *chip, unsigned int events)
35526b8f5e1SEric Miao {
35626b8f5e1SEric Miao 	uint8_t v[4];
35726b8f5e1SEric Miao 
35826b8f5e1SEric Miao 	chip->events_mask |= events;
35926b8f5e1SEric Miao 
36026b8f5e1SEric Miao 	v[0] = (chip->events_mask & 0xff);
36126b8f5e1SEric Miao 	v[1] = (chip->events_mask >> 8) & 0xff;
36226b8f5e1SEric Miao 	v[2] = (chip->events_mask >> 16) & 0xff;
36326b8f5e1SEric Miao 	v[3] = (chip->events_mask >> 24) & 0xff;
36426b8f5e1SEric Miao 
36526b8f5e1SEric Miao 	return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
36626b8f5e1SEric Miao }
36726b8f5e1SEric Miao 
da9034_read_events(struct da903x_chip * chip,unsigned int * events)36826b8f5e1SEric Miao static int da9034_read_events(struct da903x_chip *chip, unsigned int *events)
36926b8f5e1SEric Miao {
37026b8f5e1SEric Miao 	uint8_t v[4] = {0, 0, 0, 0};
37126b8f5e1SEric Miao 	int ret;
37226b8f5e1SEric Miao 
37326b8f5e1SEric Miao 	ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v);
37426b8f5e1SEric Miao 	if (ret < 0)
37526b8f5e1SEric Miao 		return ret;
37626b8f5e1SEric Miao 
37726b8f5e1SEric Miao 	*events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
37826b8f5e1SEric Miao 	return 0;
37926b8f5e1SEric Miao }
38026b8f5e1SEric Miao 
da9034_read_status(struct da903x_chip * chip,unsigned int * status)38126b8f5e1SEric Miao static int da9034_read_status(struct da903x_chip *chip, unsigned int *status)
38226b8f5e1SEric Miao {
38326b8f5e1SEric Miao 	uint8_t v[2] = {0, 0};
38426b8f5e1SEric Miao 	int ret = 0;
38526b8f5e1SEric Miao 
38626b8f5e1SEric Miao 	ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v);
38726b8f5e1SEric Miao 	if (ret)
38826b8f5e1SEric Miao 		return ret;
38926b8f5e1SEric Miao 
39026b8f5e1SEric Miao 	*status = (v[1] << 8) | v[0];
39126b8f5e1SEric Miao 	return 0;
39226b8f5e1SEric Miao }
39326b8f5e1SEric Miao 
da903x_irq_work(struct work_struct * work)39426b8f5e1SEric Miao static void da903x_irq_work(struct work_struct *work)
39526b8f5e1SEric Miao {
39626b8f5e1SEric Miao 	struct da903x_chip *chip =
39726b8f5e1SEric Miao 		container_of(work, struct da903x_chip, irq_work);
39826b8f5e1SEric Miao 	unsigned int events = 0;
39926b8f5e1SEric Miao 
40026b8f5e1SEric Miao 	while (1) {
40126b8f5e1SEric Miao 		if (chip->ops->read_events(chip, &events))
40226b8f5e1SEric Miao 			break;
40326b8f5e1SEric Miao 
40426b8f5e1SEric Miao 		events &= ~chip->events_mask;
40526b8f5e1SEric Miao 		if (events == 0)
40626b8f5e1SEric Miao 			break;
40726b8f5e1SEric Miao 
40826b8f5e1SEric Miao 		blocking_notifier_call_chain(
40926b8f5e1SEric Miao 				&chip->notifier_list, events, NULL);
41026b8f5e1SEric Miao 	}
41126b8f5e1SEric Miao 	enable_irq(chip->client->irq);
41226b8f5e1SEric Miao }
41326b8f5e1SEric Miao 
da903x_irq_handler(int irq,void * data)414fa15ce8aSSamuel Ortiz static irqreturn_t da903x_irq_handler(int irq, void *data)
41526b8f5e1SEric Miao {
41626b8f5e1SEric Miao 	struct da903x_chip *chip = data;
41726b8f5e1SEric Miao 
41826b8f5e1SEric Miao 	disable_irq_nosync(irq);
41926b8f5e1SEric Miao 	(void)schedule_work(&chip->irq_work);
42026b8f5e1SEric Miao 
42126b8f5e1SEric Miao 	return IRQ_HANDLED;
42226b8f5e1SEric Miao }
42326b8f5e1SEric Miao 
424f83e7d81SJulia Lawall static const struct da903x_chip_ops da903x_ops[] = {
42526b8f5e1SEric Miao 	[0] = {
42626b8f5e1SEric Miao 		.init_chip	= da9030_init_chip,
42726b8f5e1SEric Miao 		.unmask_events	= da9030_unmask_events,
42826b8f5e1SEric Miao 		.mask_events	= da9030_mask_events,
42926b8f5e1SEric Miao 		.read_events	= da9030_read_events,
43026b8f5e1SEric Miao 		.read_status	= da9030_read_status,
43126b8f5e1SEric Miao 	},
43226b8f5e1SEric Miao 	[1] = {
43326b8f5e1SEric Miao 		.init_chip	= da9034_init_chip,
43426b8f5e1SEric Miao 		.unmask_events	= da9034_unmask_events,
43526b8f5e1SEric Miao 		.mask_events	= da9034_mask_events,
43626b8f5e1SEric Miao 		.read_events	= da9034_read_events,
43726b8f5e1SEric Miao 		.read_status	= da9034_read_status,
43826b8f5e1SEric Miao 	}
43926b8f5e1SEric Miao };
44026b8f5e1SEric Miao 
44126b8f5e1SEric Miao static const struct i2c_device_id da903x_id_table[] = {
44226b8f5e1SEric Miao 	{ "da9030", 0 },
44326b8f5e1SEric Miao 	{ "da9034", 1 },
44426b8f5e1SEric Miao 	{ },
44526b8f5e1SEric Miao };
44626b8f5e1SEric Miao MODULE_DEVICE_TABLE(i2c, da903x_id_table);
44726b8f5e1SEric Miao 
__remove_subdev(struct device * dev,void * unused)4483f874b66SMark Brown static int __remove_subdev(struct device *dev, void *unused)
44926b8f5e1SEric Miao {
45026b8f5e1SEric Miao 	platform_device_unregister(to_platform_device(dev));
45126b8f5e1SEric Miao 	return 0;
45226b8f5e1SEric Miao }
45326b8f5e1SEric Miao 
da903x_remove_subdevs(struct da903x_chip * chip)4543f874b66SMark Brown static int da903x_remove_subdevs(struct da903x_chip *chip)
45526b8f5e1SEric Miao {
45626b8f5e1SEric Miao 	return device_for_each_child(chip->dev, NULL, __remove_subdev);
45726b8f5e1SEric Miao }
45826b8f5e1SEric Miao 
da903x_add_subdevs(struct da903x_chip * chip,struct da903x_platform_data * pdata)459f791be49SBill Pemberton static int da903x_add_subdevs(struct da903x_chip *chip,
46026b8f5e1SEric Miao 					struct da903x_platform_data *pdata)
46126b8f5e1SEric Miao {
46226b8f5e1SEric Miao 	struct da903x_subdev_info *subdev;
46326b8f5e1SEric Miao 	struct platform_device *pdev;
46426b8f5e1SEric Miao 	int i, ret = 0;
46526b8f5e1SEric Miao 
46626b8f5e1SEric Miao 	for (i = 0; i < pdata->num_subdevs; i++) {
46726b8f5e1SEric Miao 		subdev = &pdata->subdevs[i];
46826b8f5e1SEric Miao 
46926b8f5e1SEric Miao 		pdev = platform_device_alloc(subdev->name, subdev->id);
470b59cedefSAxel Lin 		if (!pdev) {
471b59cedefSAxel Lin 			ret = -ENOMEM;
472b59cedefSAxel Lin 			goto failed;
473b59cedefSAxel Lin 		}
47426b8f5e1SEric Miao 
47526b8f5e1SEric Miao 		pdev->dev.parent = chip->dev;
47626b8f5e1SEric Miao 		pdev->dev.platform_data = subdev->platform_data;
47726b8f5e1SEric Miao 
47826b8f5e1SEric Miao 		ret = platform_device_add(pdev);
479b59cedefSAxel Lin 		if (ret) {
480b59cedefSAxel Lin 			platform_device_put(pdev);
48126b8f5e1SEric Miao 			goto failed;
48226b8f5e1SEric Miao 		}
483b59cedefSAxel Lin 	}
48426b8f5e1SEric Miao 	return 0;
48526b8f5e1SEric Miao 
48626b8f5e1SEric Miao failed:
48726b8f5e1SEric Miao 	da903x_remove_subdevs(chip);
48826b8f5e1SEric Miao 	return ret;
48926b8f5e1SEric Miao }
49026b8f5e1SEric Miao 
da903x_probe(struct i2c_client * client)4916887bb93SUwe Kleine-König static int da903x_probe(struct i2c_client *client)
49226b8f5e1SEric Miao {
4936887bb93SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
494334a41ceSJingoo Han 	struct da903x_platform_data *pdata = dev_get_platdata(&client->dev);
49526b8f5e1SEric Miao 	struct da903x_chip *chip;
49626b8f5e1SEric Miao 	unsigned int tmp;
49726b8f5e1SEric Miao 	int ret;
49826b8f5e1SEric Miao 
499aa4dcf5bSJingoo Han 	chip = devm_kzalloc(&client->dev, sizeof(struct da903x_chip),
500aa4dcf5bSJingoo Han 				GFP_KERNEL);
50126b8f5e1SEric Miao 	if (chip == NULL)
50226b8f5e1SEric Miao 		return -ENOMEM;
50326b8f5e1SEric Miao 
50426b8f5e1SEric Miao 	chip->client = client;
50526b8f5e1SEric Miao 	chip->dev = &client->dev;
50626b8f5e1SEric Miao 	chip->ops = &da903x_ops[id->driver_data];
50726b8f5e1SEric Miao 
50826b8f5e1SEric Miao 	mutex_init(&chip->lock);
50926b8f5e1SEric Miao 	INIT_WORK(&chip->irq_work, da903x_irq_work);
51026b8f5e1SEric Miao 	BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
51126b8f5e1SEric Miao 
51226b8f5e1SEric Miao 	i2c_set_clientdata(client, chip);
51326b8f5e1SEric Miao 
51426b8f5e1SEric Miao 	ret = chip->ops->init_chip(chip);
51526b8f5e1SEric Miao 	if (ret)
516aa4dcf5bSJingoo Han 		return ret;
51726b8f5e1SEric Miao 
51826b8f5e1SEric Miao 	/* mask and clear all IRQs */
51926b8f5e1SEric Miao 	chip->events_mask = 0xffffffff;
52026b8f5e1SEric Miao 	chip->ops->mask_events(chip, chip->events_mask);
52126b8f5e1SEric Miao 	chip->ops->read_events(chip, &tmp);
52226b8f5e1SEric Miao 
523aa4dcf5bSJingoo Han 	ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler,
524f742b96eSYong Zhang 			IRQF_TRIGGER_FALLING,
52526b8f5e1SEric Miao 			"da903x", chip);
52626b8f5e1SEric Miao 	if (ret) {
52726b8f5e1SEric Miao 		dev_err(&client->dev, "failed to request irq %d\n",
52826b8f5e1SEric Miao 				client->irq);
529aa4dcf5bSJingoo Han 		return ret;
53026b8f5e1SEric Miao 	}
53126b8f5e1SEric Miao 
5325597da29SJavier Martinez Canillas 	return da903x_add_subdevs(chip, pdata);
53326b8f5e1SEric Miao }
53426b8f5e1SEric Miao 
da903x_remove(struct i2c_client * client)535ed5c2f5fSUwe Kleine-König static void da903x_remove(struct i2c_client *client)
53626b8f5e1SEric Miao {
53726b8f5e1SEric Miao 	struct da903x_chip *chip = i2c_get_clientdata(client);
53826b8f5e1SEric Miao 
53926b8f5e1SEric Miao 	da903x_remove_subdevs(chip);
54026b8f5e1SEric Miao }
54126b8f5e1SEric Miao 
54226b8f5e1SEric Miao static struct i2c_driver da903x_driver = {
54326b8f5e1SEric Miao 	.driver	= {
54426b8f5e1SEric Miao 		.name	= "da903x",
54526b8f5e1SEric Miao 	},
546*9816d859SUwe Kleine-König 	.probe		= da903x_probe,
54784449216SBill Pemberton 	.remove		= da903x_remove,
54826b8f5e1SEric Miao 	.id_table	= da903x_id_table,
54926b8f5e1SEric Miao };
55026b8f5e1SEric Miao 
da903x_init(void)55126b8f5e1SEric Miao static int __init da903x_init(void)
55226b8f5e1SEric Miao {
55326b8f5e1SEric Miao 	return i2c_add_driver(&da903x_driver);
55426b8f5e1SEric Miao }
5552021de87SSamuel Ortiz subsys_initcall(da903x_init);
55626b8f5e1SEric Miao 
da903x_exit(void)55726b8f5e1SEric Miao static void __exit da903x_exit(void)
55826b8f5e1SEric Miao {
55926b8f5e1SEric Miao 	i2c_del_driver(&da903x_driver);
56026b8f5e1SEric Miao }
56126b8f5e1SEric Miao module_exit(da903x_exit);
56226b8f5e1SEric Miao 
56326b8f5e1SEric Miao MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034");
5648b277578SLee Jones MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
5658b277578SLee Jones MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
566