Commit | Line | Data |
---|---|---|
36e52873 MO |
1 | /* |
2 | * tps65912-core.c -- TI TPS65912x | |
3 | * | |
4 | * Copyright 2011 Texas Instruments Inc. | |
5 | * | |
6 | * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. | |
12 | * | |
13 | * This driver is based on wm8350 implementation. | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/moduleparam.h> | |
36e52873 MO |
18 | #include <linux/slab.h> |
19 | #include <linux/gpio.h> | |
20 | #include <linux/mfd/core.h> | |
21 | #include <linux/mfd/tps65912.h> | |
22 | ||
30fe2b5b | 23 | static const struct mfd_cell tps65912s[] = { |
36e52873 MO |
24 | { |
25 | .name = "tps65912-pmic", | |
26 | }, | |
27 | }; | |
28 | ||
29 | int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask) | |
30 | { | |
31 | u8 data; | |
32 | int err; | |
33 | ||
34 | mutex_lock(&tps65912->io_mutex); | |
35 | ||
36 | err = tps65912->read(tps65912, reg, 1, &data); | |
37 | if (err) { | |
38 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | |
39 | goto out; | |
40 | } | |
41 | ||
42 | data |= mask; | |
43 | err = tps65912->write(tps65912, reg, 1, &data); | |
44 | if (err) | |
45 | dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg); | |
46 | ||
47 | out: | |
48 | mutex_unlock(&tps65912->io_mutex); | |
49 | return err; | |
50 | } | |
51 | EXPORT_SYMBOL_GPL(tps65912_set_bits); | |
52 | ||
53 | int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask) | |
54 | { | |
55 | u8 data; | |
56 | int err; | |
57 | ||
58 | mutex_lock(&tps65912->io_mutex); | |
59 | err = tps65912->read(tps65912, reg, 1, &data); | |
60 | if (err) { | |
61 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | |
62 | goto out; | |
63 | } | |
64 | ||
65 | data &= ~mask; | |
66 | err = tps65912->write(tps65912, reg, 1, &data); | |
67 | if (err) | |
68 | dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg); | |
69 | ||
70 | out: | |
71 | mutex_unlock(&tps65912->io_mutex); | |
72 | return err; | |
73 | } | |
74 | EXPORT_SYMBOL_GPL(tps65912_clear_bits); | |
75 | ||
76 | static inline int tps65912_read(struct tps65912 *tps65912, u8 reg) | |
77 | { | |
78 | u8 val; | |
79 | int err; | |
80 | ||
81 | err = tps65912->read(tps65912, reg, 1, &val); | |
82 | if (err < 0) | |
83 | return err; | |
84 | ||
85 | return val; | |
86 | } | |
87 | ||
88 | static inline int tps65912_write(struct tps65912 *tps65912, u8 reg, u8 val) | |
89 | { | |
90 | return tps65912->write(tps65912, reg, 1, &val); | |
91 | } | |
92 | ||
93 | int tps65912_reg_read(struct tps65912 *tps65912, u8 reg) | |
94 | { | |
95 | int data; | |
96 | ||
97 | mutex_lock(&tps65912->io_mutex); | |
98 | ||
99 | data = tps65912_read(tps65912, reg); | |
100 | if (data < 0) | |
101 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | |
102 | ||
103 | mutex_unlock(&tps65912->io_mutex); | |
104 | return data; | |
105 | } | |
106 | EXPORT_SYMBOL_GPL(tps65912_reg_read); | |
107 | ||
108 | int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val) | |
109 | { | |
110 | int err; | |
111 | ||
112 | mutex_lock(&tps65912->io_mutex); | |
113 | ||
114 | err = tps65912_write(tps65912, reg, val); | |
115 | if (err < 0) | |
116 | dev_err(tps65912->dev, "Write for reg 0x%x failed\n", reg); | |
117 | ||
118 | mutex_unlock(&tps65912->io_mutex); | |
119 | return err; | |
120 | } | |
121 | EXPORT_SYMBOL_GPL(tps65912_reg_write); | |
122 | ||
123 | int tps65912_device_init(struct tps65912 *tps65912) | |
124 | { | |
334a41ce | 125 | struct tps65912_board *pmic_plat_data = dev_get_platdata(tps65912->dev); |
d49a0f3f | 126 | struct tps65912_platform_data *init_data; |
36e52873 MO |
127 | int ret, dcdc_avs, value; |
128 | ||
d49a0f3f MO |
129 | init_data = kzalloc(sizeof(struct tps65912_platform_data), GFP_KERNEL); |
130 | if (init_data == NULL) | |
131 | return -ENOMEM; | |
132 | ||
36e52873 MO |
133 | mutex_init(&tps65912->io_mutex); |
134 | dev_set_drvdata(tps65912->dev, tps65912); | |
135 | ||
136 | dcdc_avs = (pmic_plat_data->is_dcdc1_avs << 0 | | |
137 | pmic_plat_data->is_dcdc2_avs << 1 | | |
138 | pmic_plat_data->is_dcdc3_avs << 2 | | |
139 | pmic_plat_data->is_dcdc4_avs << 3); | |
140 | if (dcdc_avs) { | |
141 | tps65912->read(tps65912, TPS65912_I2C_SPI_CFG, 1, &value); | |
142 | dcdc_avs |= value; | |
143 | tps65912->write(tps65912, TPS65912_I2C_SPI_CFG, 1, &dcdc_avs); | |
144 | } | |
145 | ||
146 | ret = mfd_add_devices(tps65912->dev, -1, | |
147 | tps65912s, ARRAY_SIZE(tps65912s), | |
0848c94f | 148 | NULL, 0, NULL); |
36e52873 MO |
149 | if (ret < 0) |
150 | goto err; | |
151 | ||
677df0c9 | 152 | init_data->irq = pmic_plat_data->irq; |
d5f39d38 | 153 | init_data->irq_base = pmic_plat_data->irq_base; |
d49a0f3f MO |
154 | ret = tps65912_irq_init(tps65912, init_data->irq, init_data); |
155 | if (ret < 0) | |
156 | goto err; | |
157 | ||
677df0c9 | 158 | kfree(init_data); |
36e52873 MO |
159 | return ret; |
160 | ||
161 | err: | |
d49a0f3f | 162 | kfree(init_data); |
36e52873 | 163 | mfd_remove_devices(tps65912->dev); |
36e52873 MO |
164 | return ret; |
165 | } | |
166 | ||
167 | void tps65912_device_exit(struct tps65912 *tps65912) | |
168 | { | |
169 | mfd_remove_devices(tps65912->dev); | |
80e4e671 | 170 | tps65912_irq_exit(tps65912); |
36e52873 MO |
171 | } |
172 | ||
173 | MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>"); | |
174 | MODULE_DESCRIPTION("TPS65912x chip family multi-function driver"); | |
175 | MODULE_LICENSE("GPL"); |