diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2012-11-19 22:14:49 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-11-21 10:07:53 -0500 |
commit | 759f2598ef3876637e40d99a4ceb7a3d83a4d8d3 (patch) | |
tree | 62fa9fd103c1c305214b7aea168f6352aa1a61bb /drivers/mfd | |
parent | b9c79323166530a14c1fa8c10337eeaa54e3f98d (diff) |
mfd: tps65090: Use regmap irq framework for interrupt support
Use the regmap irq framework for implementing TPS65090 interrupt
support in place of implementing it locally.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/tps65090.c | 263 |
1 files changed, 98 insertions, 165 deletions
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 355a07749454..2eaae52cb5b8 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
@@ -38,35 +38,21 @@ | |||
38 | #define TPS65090_INT_MSK 0x2 | 38 | #define TPS65090_INT_MSK 0x2 |
39 | #define TPS65090_INT_MSK2 0x3 | 39 | #define TPS65090_INT_MSK2 0x3 |
40 | 40 | ||
41 | struct tps65090_irq_data { | 41 | #define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1 |
42 | u8 mask_reg; | 42 | #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2 |
43 | u8 mask_pos; | 43 | #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3 |
44 | }; | 44 | #define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE 4 |
45 | 45 | #define TPS65090_INT1_MASK_CHARGING_COMPLETE 5 | |
46 | #define TPS65090_IRQ(_reg, _mask_pos) \ | 46 | #define TPS65090_INT1_MASK_OVERLOAD_DCDC1 6 |
47 | { \ | 47 | #define TPS65090_INT1_MASK_OVERLOAD_DCDC2 7 |
48 | .mask_reg = (_reg), \ | 48 | #define TPS65090_INT2_MASK_OVERLOAD_DCDC3 0 |
49 | .mask_pos = (_mask_pos), \ | 49 | #define TPS65090_INT2_MASK_OVERLOAD_FET1 1 |
50 | } | 50 | #define TPS65090_INT2_MASK_OVERLOAD_FET2 2 |
51 | 51 | #define TPS65090_INT2_MASK_OVERLOAD_FET3 3 | |
52 | static const struct tps65090_irq_data tps65090_irqs[] = { | 52 | #define TPS65090_INT2_MASK_OVERLOAD_FET4 4 |
53 | [0] = TPS65090_IRQ(0, 0), | 53 | #define TPS65090_INT2_MASK_OVERLOAD_FET5 5 |
54 | [1] = TPS65090_IRQ(0, 1), | 54 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 |
55 | [2] = TPS65090_IRQ(0, 2), | 55 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 |
56 | [3] = TPS65090_IRQ(0, 3), | ||
57 | [4] = TPS65090_IRQ(0, 4), | ||
58 | [5] = TPS65090_IRQ(0, 5), | ||
59 | [6] = TPS65090_IRQ(0, 6), | ||
60 | [7] = TPS65090_IRQ(0, 7), | ||
61 | [8] = TPS65090_IRQ(1, 0), | ||
62 | [9] = TPS65090_IRQ(1, 1), | ||
63 | [10] = TPS65090_IRQ(1, 2), | ||
64 | [11] = TPS65090_IRQ(1, 3), | ||
65 | [12] = TPS65090_IRQ(1, 4), | ||
66 | [13] = TPS65090_IRQ(1, 5), | ||
67 | [14] = TPS65090_IRQ(1, 6), | ||
68 | [15] = TPS65090_IRQ(1, 7), | ||
69 | }; | ||
70 | 56 | ||
71 | static struct mfd_cell tps65090s[] = { | 57 | static struct mfd_cell tps65090s[] = { |
72 | { | 58 | { |
@@ -77,132 +63,77 @@ static struct mfd_cell tps65090s[] = { | |||
77 | }, | 63 | }, |
78 | }; | 64 | }; |
79 | 65 | ||
80 | static void tps65090_irq_lock(struct irq_data *data) | 66 | static const struct regmap_irq tps65090_irqs[] = { |
81 | { | 67 | /* INT1 IRQs*/ |
82 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data); | 68 | [TPS65090_IRQ_VAC_STATUS_CHANGE] = { |
83 | 69 | .mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE, | |
84 | mutex_lock(&tps65090->irq_lock); | 70 | }, |
85 | } | 71 | [TPS65090_IRQ_VSYS_STATUS_CHANGE] = { |
86 | 72 | .mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE, | |
87 | static void tps65090_irq_mask(struct irq_data *irq_data) | 73 | }, |
88 | { | 74 | [TPS65090_IRQ_BAT_STATUS_CHANGE] = { |
89 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data); | 75 | .mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE, |
90 | unsigned int __irq = irq_data->hwirq; | 76 | }, |
91 | const struct tps65090_irq_data *data = &tps65090_irqs[__irq]; | 77 | [TPS65090_IRQ_CHARGING_STATUS_CHANGE] = { |
92 | 78 | .mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE, | |
93 | tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg), | 79 | }, |
94 | data->mask_pos); | 80 | [TPS65090_IRQ_CHARGING_COMPLETE] = { |
95 | } | 81 | .mask = TPS65090_INT1_MASK_CHARGING_COMPLETE, |
96 | 82 | }, | |
97 | static void tps65090_irq_unmask(struct irq_data *irq_data) | 83 | [TPS65090_IRQ_OVERLOAD_DCDC1] = { |
98 | { | 84 | .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1, |
99 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data); | 85 | }, |
100 | unsigned int __irq = irq_data->irq - tps65090->irq_base; | 86 | [TPS65090_IRQ_OVERLOAD_DCDC2] = { |
101 | const struct tps65090_irq_data *data = &tps65090_irqs[__irq]; | 87 | .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2, |
102 | 88 | }, | |
103 | tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg), | 89 | /* INT2 IRQs*/ |
104 | data->mask_pos); | 90 | [TPS65090_IRQ_OVERLOAD_DCDC3] = { |
105 | } | 91 | .reg_offset = 1, |
106 | 92 | .mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3, | |
107 | static void tps65090_irq_sync_unlock(struct irq_data *data) | 93 | }, |
108 | { | 94 | [TPS65090_IRQ_OVERLOAD_FET1] = { |
109 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data); | 95 | .reg_offset = 1, |
110 | 96 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET1, | |
111 | mutex_unlock(&tps65090->irq_lock); | 97 | }, |
112 | } | 98 | [TPS65090_IRQ_OVERLOAD_FET2] = { |
113 | 99 | .reg_offset = 1, | |
114 | static irqreturn_t tps65090_irq(int irq, void *data) | 100 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET2, |
115 | { | 101 | }, |
116 | struct tps65090 *tps65090 = data; | 102 | [TPS65090_IRQ_OVERLOAD_FET3] = { |
117 | int ret = 0; | 103 | .reg_offset = 1, |
118 | u8 status, mask; | 104 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET3, |
119 | unsigned long int acks = 0; | 105 | }, |
120 | int i; | 106 | [TPS65090_IRQ_OVERLOAD_FET4] = { |
121 | 107 | .reg_offset = 1, | |
122 | for (i = 0; i < NUM_INT_REG; i++) { | 108 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET4, |
123 | ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask); | 109 | }, |
124 | if (ret < 0) { | 110 | [TPS65090_IRQ_OVERLOAD_FET5] = { |
125 | dev_err(tps65090->dev, | 111 | .reg_offset = 1, |
126 | "failed to read mask reg [addr:%d]\n", | 112 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET5, |
127 | TPS65090_INT_MSK + i); | 113 | }, |
128 | return IRQ_NONE; | 114 | [TPS65090_IRQ_OVERLOAD_FET6] = { |
129 | } | 115 | .reg_offset = 1, |
130 | ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i, | 116 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET6, |
131 | &status); | 117 | }, |
132 | if (ret < 0) { | 118 | [TPS65090_IRQ_OVERLOAD_FET7] = { |
133 | dev_err(tps65090->dev, | 119 | .reg_offset = 1, |
134 | "failed to read status reg [addr:%d]\n", | 120 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET7, |
135 | TPS65090_INT_STS + i); | 121 | }, |
136 | return IRQ_NONE; | 122 | }; |
137 | } | ||
138 | if (status) { | ||
139 | /* Ack only those interrupts which are not masked */ | ||
140 | status &= (~mask); | ||
141 | ret = tps65090_write(tps65090->dev, | ||
142 | TPS65090_INT_STS + i, status); | ||
143 | if (ret < 0) { | ||
144 | dev_err(tps65090->dev, | ||
145 | "failed to write interrupt status\n"); | ||
146 | return IRQ_NONE; | ||
147 | } | ||
148 | acks |= (status << (i * 8)); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs)) | ||
153 | handle_nested_irq(tps65090->irq_base + i); | ||
154 | return acks ? IRQ_HANDLED : IRQ_NONE; | ||
155 | } | ||
156 | |||
157 | static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq, | ||
158 | int irq_base) | ||
159 | { | ||
160 | int i, ret; | ||
161 | |||
162 | if (!irq_base) { | ||
163 | dev_err(tps65090->dev, "IRQ base not set\n"); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | mutex_init(&tps65090->irq_lock); | ||
168 | |||
169 | for (i = 0; i < NUM_INT_REG; i++) | ||
170 | tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF); | ||
171 | |||
172 | for (i = 0; i < NUM_INT_REG; i++) | ||
173 | tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff); | ||
174 | |||
175 | tps65090->irq_base = irq_base; | ||
176 | tps65090->irq_chip.name = "tps65090"; | ||
177 | tps65090->irq_chip.irq_mask = tps65090_irq_mask; | ||
178 | tps65090->irq_chip.irq_unmask = tps65090_irq_unmask; | ||
179 | tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock; | ||
180 | tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock; | ||
181 | |||
182 | for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) { | ||
183 | int __irq = i + tps65090->irq_base; | ||
184 | irq_set_chip_data(__irq, tps65090); | ||
185 | irq_set_chip_and_handler(__irq, &tps65090->irq_chip, | ||
186 | handle_simple_irq); | ||
187 | irq_set_nested_thread(__irq, 1); | ||
188 | #ifdef CONFIG_ARM | ||
189 | set_irq_flags(__irq, IRQF_VALID); | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT, | ||
194 | "tps65090", tps65090); | ||
195 | if (!ret) { | ||
196 | device_init_wakeup(tps65090->dev, 1); | ||
197 | enable_irq_wake(irq); | ||
198 | } | ||
199 | 123 | ||
200 | return ret; | 124 | static struct regmap_irq_chip tps65090_irq_chip = { |
201 | } | 125 | .name = "tps65090", |
126 | .irqs = tps65090_irqs, | ||
127 | .num_irqs = ARRAY_SIZE(tps65090_irqs), | ||
128 | .num_regs = NUM_INT_REG, | ||
129 | .status_base = TPS65090_INT_STS, | ||
130 | .mask_base = TPS65090_INT_MSK, | ||
131 | .mask_invert = true, | ||
132 | }; | ||
202 | 133 | ||
203 | static bool is_volatile_reg(struct device *dev, unsigned int reg) | 134 | static bool is_volatile_reg(struct device *dev, unsigned int reg) |
204 | { | 135 | { |
205 | if (reg == TPS65090_INT_STS) | 136 | if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2)) |
206 | return true; | 137 | return true; |
207 | else | 138 | else |
208 | return false; | 139 | return false; |
@@ -238,24 +169,27 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client, | |||
238 | tps65090->dev = &client->dev; | 169 | tps65090->dev = &client->dev; |
239 | i2c_set_clientdata(client, tps65090); | 170 | i2c_set_clientdata(client, tps65090); |
240 | 171 | ||
241 | if (client->irq) { | ||
242 | ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base); | ||
243 | if (ret) { | ||
244 | dev_err(&client->dev, "IRQ init failed with err: %d\n", | ||
245 | ret); | ||
246 | goto err_exit; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config); | 172 | tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config); |
251 | if (IS_ERR(tps65090->rmap)) { | 173 | if (IS_ERR(tps65090->rmap)) { |
252 | ret = PTR_ERR(tps65090->rmap); | 174 | ret = PTR_ERR(tps65090->rmap); |
253 | dev_err(&client->dev, "regmap_init failed with err: %d\n", ret); | 175 | dev_err(&client->dev, "regmap_init failed with err: %d\n", ret); |
254 | goto err_irq_exit; | 176 | return ret; |
177 | } | ||
178 | |||
179 | if (client->irq) { | ||
180 | ret = regmap_add_irq_chip(tps65090->rmap, client->irq, | ||
181 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, pdata->irq_base, | ||
182 | &tps65090_irq_chip, &tps65090->irq_data); | ||
183 | if (ret) { | ||
184 | dev_err(&client->dev, | ||
185 | "IRQ init failed with err: %d\n", ret); | ||
186 | return ret; | ||
187 | } | ||
255 | } | 188 | } |
256 | 189 | ||
257 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, | 190 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, |
258 | ARRAY_SIZE(tps65090s), NULL, 0, NULL); | 191 | ARRAY_SIZE(tps65090s), NULL, |
192 | regmap_irq_chip_get_base(tps65090->irq_data), NULL); | ||
259 | if (ret) { | 193 | if (ret) { |
260 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", | 194 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", |
261 | ret); | 195 | ret); |
@@ -266,8 +200,7 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client, | |||
266 | 200 | ||
267 | err_irq_exit: | 201 | err_irq_exit: |
268 | if (client->irq) | 202 | if (client->irq) |
269 | free_irq(client->irq, tps65090); | 203 | regmap_del_irq_chip(client->irq, tps65090->irq_data); |
270 | err_exit: | ||
271 | return ret; | 204 | return ret; |
272 | } | 205 | } |
273 | 206 | ||
@@ -277,7 +210,7 @@ static int __devexit tps65090_i2c_remove(struct i2c_client *client) | |||
277 | 210 | ||
278 | mfd_remove_devices(tps65090->dev); | 211 | mfd_remove_devices(tps65090->dev); |
279 | if (client->irq) | 212 | if (client->irq) |
280 | free_irq(client->irq, tps65090); | 213 | regmap_del_irq_chip(client->irq, tps65090->irq_data); |
281 | 214 | ||
282 | return 0; | 215 | return 0; |
283 | } | 216 | } |