aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd/rt5033.c
blob: 7e23ab3d5842c8b4d49e0206e03ba27f9f4e0c5f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: GPL-2.0-only
/*
 * MFD core driver for the Richtek RT5033.
 *
 * RT5033 comprises multiple sub-devices switcing charger, fuel gauge,
 * flash LED, current source, LDO and BUCK regulators.
 *
 * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
 * Author: Beomho Seo <beomho.seo@samsung.com>
 */

#include <linux/err.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rt5033.h>
#include <linux/mfd/rt5033-private.h>

static const struct regmap_irq rt5033_irqs[] = {
	{ .mask = RT5033_PMIC_IRQ_BUCKOCP, },
	{ .mask = RT5033_PMIC_IRQ_BUCKLV, },
	{ .mask = RT5033_PMIC_IRQ_SAFELDOLV, },
	{ .mask = RT5033_PMIC_IRQ_LDOLV, },
	{ .mask = RT5033_PMIC_IRQ_OT, },
	{ .mask = RT5033_PMIC_IRQ_VDDA_UV, },
};

static const struct regmap_irq_chip rt5033_irq_chip = {
	.name		= "rt5033",
	.status_base	= RT5033_REG_PMIC_IRQ_STAT,
	.unmask_base	= RT5033_REG_PMIC_IRQ_CTRL,
	.num_regs	= 1,
	.irqs		= rt5033_irqs,
	.num_irqs	= ARRAY_SIZE(rt5033_irqs),
};

static const struct mfd_cell rt5033_devs[] = {
	{ .name = "rt5033-regulator", },
	{
		.name = "rt5033-charger",
		.of_compatible = "richtek,rt5033-charger",
	}, {
		.name = "rt5033-led",
		.of_compatible = "richtek,rt5033-led",
	},
};

static const struct regmap_config rt5033_regmap_config = {
	.reg_bits	= 8,
	.val_bits	= 8,
	.max_register	= RT5033_REG_END,
};

static int rt5033_i2c_probe(struct i2c_client *i2c)
{
	struct rt5033_dev *rt5033;
	unsigned int dev_id, chip_rev;
	int ret;

	rt5033 = devm_kzalloc(&i2c->dev, sizeof(*rt5033), GFP_KERNEL);
	if (!rt5033)
		return -ENOMEM;

	i2c_set_clientdata(i2c, rt5033);
	rt5033->dev = &i2c->dev;
	rt5033->irq = i2c->irq;
	rt5033->wakeup = true;

	rt5033->regmap = devm_regmap_init_i2c(i2c, &rt5033_regmap_config);
	if (IS_ERR(rt5033->regmap)) {
		dev_err(&i2c->dev, "Failed to allocate register map.\n");
		return PTR_ERR(rt5033->regmap);
	}

	ret = regmap_read(rt5033->regmap, RT5033_REG_DEVICE_ID, &dev_id);
	if (ret) {
		dev_err(&i2c->dev, "Device not found\n");
		return -ENODEV;
	}
	chip_rev = dev_id & RT5033_CHIP_REV_MASK;
	dev_info(&i2c->dev, "Device found (rev. %d)\n", chip_rev);

	ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq,
			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
			0, &rt5033_irq_chip, &rt5033->irq_data);
	if (ret) {
		dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
							rt5033->irq, ret);
		return ret;
	}

	ret = devm_mfd_add_devices(rt5033->dev, -1, rt5033_devs,
				   ARRAY_SIZE(rt5033_devs), NULL, 0,
				   regmap_irq_get_domain(rt5033->irq_data));
	if (ret < 0) {
		dev_err(&i2c->dev, "Failed to add RT5033 child devices.\n");
		return ret;
	}

	device_init_wakeup(rt5033->dev, rt5033->wakeup);

	return 0;
}

static const struct i2c_device_id rt5033_i2c_id[] = {
	{ "rt5033", },
	{ }
};
MODULE_DEVICE_TABLE(i2c, rt5033_i2c_id);

static const struct of_device_id rt5033_dt_match[] = {
	{ .compatible = "richtek,rt5033", },
	{ }
};
MODULE_DEVICE_TABLE(of, rt5033_dt_match);

static struct i2c_driver rt5033_driver = {
	.driver = {
		.name = "rt5033",
		.of_match_table = rt5033_dt_match,
	},
	.probe = rt5033_i2c_probe,
	.id_table = rt5033_i2c_id,
};
module_i2c_driver(rt5033_driver);

MODULE_DESCRIPTION("Richtek RT5033 multi-function core driver");
MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
MODULE_LICENSE("GPL");