Blame view
drivers/mfd/tps65090.c
7.28 KB
3c33be06f
|
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 |
/* * Core driver for TI TPS65090 PMIC family * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/mfd/core.h> #include <linux/mfd/tps65090.h> |
40719314f
|
28 29 |
#include <linux/of.h> #include <linux/of_device.h> |
3c33be06f
|
30 31 32 |
#include <linux/err.h> #define NUM_INT_REG 2 |
3c33be06f
|
33 |
|
759f2598e
|
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1 #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2 #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3 #define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE 4 #define TPS65090_INT1_MASK_CHARGING_COMPLETE 5 #define TPS65090_INT1_MASK_OVERLOAD_DCDC1 6 #define TPS65090_INT1_MASK_OVERLOAD_DCDC2 7 #define TPS65090_INT2_MASK_OVERLOAD_DCDC3 0 #define TPS65090_INT2_MASK_OVERLOAD_FET1 1 #define TPS65090_INT2_MASK_OVERLOAD_FET2 2 #define TPS65090_INT2_MASK_OVERLOAD_FET3 3 #define TPS65090_INT2_MASK_OVERLOAD_FET4 4 #define TPS65090_INT2_MASK_OVERLOAD_FET5 5 #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 |
3c33be06f
|
49 |
|
36c772e31
|
50 51 52 53 54 55 56 |
static struct resource charger_resources[] = { { .start = TPS65090_IRQ_VAC_STATUS_CHANGE, .end = TPS65090_IRQ_VAC_STATUS_CHANGE, .flags = IORESOURCE_IRQ, } }; |
7d811771c
|
57 58 59 60 61 62 63 |
enum tps65090_cells { PMIC = 0, CHARGER = 1, }; static struct mfd_cell tps65090s[] = { [PMIC] = { |
b7e537861
|
64 |
.name = "tps65090-pmic", |
3c33be06f
|
65 |
}, |
7d811771c
|
66 |
[CHARGER] = { |
e2e8ffc97
|
67 |
.name = "tps65090-charger", |
36c772e31
|
68 69 |
.num_resources = ARRAY_SIZE(charger_resources), .resources = &charger_resources[0], |
b50cf35bf
|
70 |
.of_compatible = "ti,tps65090-charger", |
3c33be06f
|
71 72 |
}, }; |
759f2598e
|
73 74 75 |
static const struct regmap_irq tps65090_irqs[] = { /* INT1 IRQs*/ [TPS65090_IRQ_VAC_STATUS_CHANGE] = { |
12849b63a
|
76 |
.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE, |
759f2598e
|
77 78 |
}, [TPS65090_IRQ_VSYS_STATUS_CHANGE] = { |
12849b63a
|
79 |
.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE, |
759f2598e
|
80 81 |
}, [TPS65090_IRQ_BAT_STATUS_CHANGE] = { |
12849b63a
|
82 |
.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE, |
759f2598e
|
83 84 |
}, [TPS65090_IRQ_CHARGING_STATUS_CHANGE] = { |
12849b63a
|
85 |
.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE, |
759f2598e
|
86 87 |
}, [TPS65090_IRQ_CHARGING_COMPLETE] = { |
12849b63a
|
88 |
.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE, |
759f2598e
|
89 90 |
}, [TPS65090_IRQ_OVERLOAD_DCDC1] = { |
12849b63a
|
91 |
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1, |
759f2598e
|
92 93 |
}, [TPS65090_IRQ_OVERLOAD_DCDC2] = { |
12849b63a
|
94 |
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2, |
759f2598e
|
95 96 97 |
}, /* INT2 IRQs*/ [TPS65090_IRQ_OVERLOAD_DCDC3] = { |
12849b63a
|
98 99 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3, |
759f2598e
|
100 101 |
}, [TPS65090_IRQ_OVERLOAD_FET1] = { |
12849b63a
|
102 103 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET1, |
759f2598e
|
104 105 |
}, [TPS65090_IRQ_OVERLOAD_FET2] = { |
12849b63a
|
106 107 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET2, |
759f2598e
|
108 109 |
}, [TPS65090_IRQ_OVERLOAD_FET3] = { |
12849b63a
|
110 111 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET3, |
759f2598e
|
112 113 |
}, [TPS65090_IRQ_OVERLOAD_FET4] = { |
12849b63a
|
114 115 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET4, |
759f2598e
|
116 117 |
}, [TPS65090_IRQ_OVERLOAD_FET5] = { |
12849b63a
|
118 119 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET5, |
759f2598e
|
120 121 |
}, [TPS65090_IRQ_OVERLOAD_FET6] = { |
12849b63a
|
122 123 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET6, |
759f2598e
|
124 125 |
}, [TPS65090_IRQ_OVERLOAD_FET7] = { |
12849b63a
|
126 127 |
.reg_offset = 1, .mask = TPS65090_INT2_MASK_OVERLOAD_FET7, |
759f2598e
|
128 129 |
}, }; |
3c33be06f
|
130 |
|
759f2598e
|
131 132 133 134 135 |
static struct regmap_irq_chip tps65090_irq_chip = { .name = "tps65090", .irqs = tps65090_irqs, .num_irqs = ARRAY_SIZE(tps65090_irqs), .num_regs = NUM_INT_REG, |
c42ba72ec
|
136 137 |
.status_base = TPS65090_REG_INTR_STS, .mask_base = TPS65090_REG_INTR_MASK, |
759f2598e
|
138 139 |
.mask_invert = true, }; |
3c33be06f
|
140 141 142 |
static bool is_volatile_reg(struct device *dev, unsigned int reg) { |
c42ba72ec
|
143 144 145 146 147 148 149 150 151 152 |
/* Nearly all registers have status bits mixed in, except a few */ switch (reg) { case TPS65090_REG_INTR_MASK: case TPS65090_REG_INTR_MASK2: case TPS65090_REG_CG_CTRL0: case TPS65090_REG_CG_CTRL1: case TPS65090_REG_CG_CTRL2: case TPS65090_REG_CG_CTRL3: case TPS65090_REG_CG_CTRL4: case TPS65090_REG_CG_CTRL5: |
3c33be06f
|
153 |
return false; |
c42ba72ec
|
154 155 |
} return true; |
3c33be06f
|
156 157 158 159 160 |
} static const struct regmap_config tps65090_regmap_config = { .reg_bits = 8, .val_bits = 8, |
5c1488906
|
161 162 |
.max_register = TPS65090_MAX_REG, .num_reg_defaults_raw = TPS65090_NUM_REGS, |
3c33be06f
|
163 164 165 |
.cache_type = REGCACHE_RBTREE, .volatile_reg = is_volatile_reg, }; |
40719314f
|
166 167 168 169 170 171 172 |
#ifdef CONFIG_OF static const struct of_device_id tps65090_of_match[] = { { .compatible = "ti,tps65090",}, {}, }; MODULE_DEVICE_TABLE(of, tps65090_of_match); #endif |
f791be492
|
173 |
static int tps65090_i2c_probe(struct i2c_client *client, |
12849b63a
|
174 |
const struct i2c_device_id *id) |
3c33be06f
|
175 |
{ |
334a41ce9
|
176 |
struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev); |
40719314f
|
177 |
int irq_base = 0; |
3c33be06f
|
178 179 |
struct tps65090 *tps65090; int ret; |
40719314f
|
180 181 182 183 |
if (!pdata && !client->dev.of_node) { dev_err(&client->dev, "tps65090 requires platform data or of_node "); |
3c33be06f
|
184 185 |
return -EINVAL; } |
40719314f
|
186 187 |
if (pdata) irq_base = pdata->irq_base; |
e8e6f047e
|
188 189 190 191 |
tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL); if (!tps65090) { dev_err(&client->dev, "mem alloc for tps65090 failed "); |
3c33be06f
|
192 |
return -ENOMEM; |
e8e6f047e
|
193 |
} |
3c33be06f
|
194 |
|
3c33be06f
|
195 196 |
tps65090->dev = &client->dev; i2c_set_clientdata(client, tps65090); |
3863db3e8
|
197 |
tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config); |
3c33be06f
|
198 |
if (IS_ERR(tps65090->rmap)) { |
b683a0a67
|
199 200 201 |
ret = PTR_ERR(tps65090->rmap); dev_err(&client->dev, "regmap_init failed with err: %d ", ret); |
759f2598e
|
202 203 204 205 206 |
return ret; } if (client->irq) { ret = regmap_add_irq_chip(tps65090->rmap, client->irq, |
12849b63a
|
207 208 209 210 211 212 |
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base, &tps65090_irq_chip, &tps65090->irq_data); if (ret) { dev_err(&client->dev, "IRQ init failed with err: %d ", ret); |
759f2598e
|
213 214 |
return ret; } |
7d811771c
|
215 216 217 |
} else { /* Don't tell children they have an IRQ that'll never fire */ tps65090s[CHARGER].num_resources = 0; |
b683a0a67
|
218 |
} |
3c33be06f
|
219 220 |
ret = mfd_add_devices(tps65090->dev, -1, tps65090s, |
12849b63a
|
221 222 |
ARRAY_SIZE(tps65090s), NULL, 0, regmap_irq_get_domain(tps65090->irq_data)); |
3c33be06f
|
223 224 225 226 |
if (ret) { dev_err(&client->dev, "add mfd devices failed with err: %d ", ret); |
1d88f7a01
|
227 |
goto err_irq_exit; |
3c33be06f
|
228 229 230 |
} return 0; |
3c33be06f
|
231 232 |
err_irq_exit: if (client->irq) |
759f2598e
|
233 |
regmap_del_irq_chip(client->irq, tps65090->irq_data); |
3c33be06f
|
234 235 |
return ret; } |
4740f73fe
|
236 |
static int tps65090_i2c_remove(struct i2c_client *client) |
3c33be06f
|
237 238 239 240 |
{ struct tps65090 *tps65090 = i2c_get_clientdata(client); mfd_remove_devices(tps65090->dev); |
3c33be06f
|
241 |
if (client->irq) |
759f2598e
|
242 |
regmap_del_irq_chip(client->irq, tps65090->irq_data); |
3c33be06f
|
243 244 245 |
return 0; } |
3c33be06f
|
246 247 248 249 250 251 252 253 254 |
static const struct i2c_device_id tps65090_id_table[] = { { "tps65090", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, tps65090_id_table); static struct i2c_driver tps65090_driver = { .driver = { .name = "tps65090", |
40719314f
|
255 |
.of_match_table = of_match_ptr(tps65090_of_match), |
3c33be06f
|
256 257 |
}, .probe = tps65090_i2c_probe, |
84449216b
|
258 |
.remove = tps65090_i2c_remove, |
3c33be06f
|
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
.id_table = tps65090_id_table, }; static int __init tps65090_init(void) { return i2c_add_driver(&tps65090_driver); } subsys_initcall(tps65090_init); static void __exit tps65090_exit(void) { i2c_del_driver(&tps65090_driver); } module_exit(tps65090_exit); MODULE_DESCRIPTION("TPS65090 core driver"); MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>"); MODULE_LICENSE("GPL v2"); |