aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2013-04-09 15:51:25 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-04-18 18:45:20 -0400
commit95e50f6a2fe9ece6503e355400c171e0f5de61be (patch)
treed3eb87597fbe75b035e6c73887190a99edddc33f /drivers/mfd
parent360e64d8bbe7c78784d769a60d152804f5079577 (diff)
mfd: retu: Add Tahvo support
Tahvo is a multi-function device on Nokia 770, implementing USB transceiver and charge/battery control. It's so close to Retu that a single driver can support both. Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig6
-rw-r--r--drivers/mfd/retu-mfd.c85
2 files changed, 78 insertions, 13 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2f3ce1836181..9de05020c660 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -371,13 +371,13 @@ config MFD_VIPERBOARD
371 The drivers do not support all features the board exposes. 371 The drivers do not support all features the board exposes.
372 372
373config MFD_RETU 373config MFD_RETU
374 tristate "Nokia Retu multi-function device" 374 tristate "Nokia Retu and Tahvo multi-function device"
375 select MFD_CORE 375 select MFD_CORE
376 depends on I2C && GENERIC_HARDIRQS 376 depends on I2C && GENERIC_HARDIRQS
377 select REGMAP_IRQ 377 select REGMAP_IRQ
378 help 378 help
379 Retu is a multi-function device found on Nokia Internet Tablets 379 Retu and Tahvo are a multi-function devices found on Nokia
380 (770, N800 and N810). 380 Internet Tablets (770, N800 and N810).
381 381
382config MFD_PCF50633 382config MFD_PCF50633
383 tristate "NXP PCF50633" 383 tristate "NXP PCF50633"
diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c
index 3ba048655bf3..a1830986eeb7 100644
--- a/drivers/mfd/retu-mfd.c
+++ b/drivers/mfd/retu-mfd.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Retu MFD driver 2 * Retu/Tahvo MFD driver
3 * 3 *
4 * Copyright (C) 2004, 2005 Nokia Corporation 4 * Copyright (C) 2004, 2005 Nokia Corporation
5 * 5 *
@@ -33,7 +33,8 @@
33#define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ 33#define RETU_REG_ASICR 0x00 /* ASIC ID and revision */
34#define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ 34#define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */
35#define RETU_REG_IDR 0x01 /* Interrupt ID */ 35#define RETU_REG_IDR 0x01 /* Interrupt ID */
36#define RETU_REG_IMR 0x02 /* Interrupt mask */ 36#define RETU_REG_IMR 0x02 /* Interrupt mask (Retu) */
37#define TAHVO_REG_IMR 0x03 /* Interrupt mask (Tahvo) */
37 38
38/* Interrupt sources */ 39/* Interrupt sources */
39#define RETU_INT_PWR 0 /* Power button */ 40#define RETU_INT_PWR 0 /* Power button */
@@ -84,6 +85,62 @@ static struct regmap_irq_chip retu_irq_chip = {
84/* Retu device registered for the power off. */ 85/* Retu device registered for the power off. */
85static struct retu_dev *retu_pm_power_off; 86static struct retu_dev *retu_pm_power_off;
86 87
88static struct resource tahvo_usb_res[] = {
89 {
90 .name = "tahvo-usb",
91 .start = TAHVO_INT_VBUS,
92 .end = TAHVO_INT_VBUS,
93 .flags = IORESOURCE_IRQ,
94 },
95};
96
97static struct mfd_cell tahvo_devs[] = {
98 {
99 .name = "tahvo-usb",
100 .resources = tahvo_usb_res,
101 .num_resources = ARRAY_SIZE(tahvo_usb_res),
102 },
103};
104
105static struct regmap_irq tahvo_irqs[] = {
106 [TAHVO_INT_VBUS] = {
107 .mask = 1 << TAHVO_INT_VBUS,
108 }
109};
110
111static struct regmap_irq_chip tahvo_irq_chip = {
112 .name = "TAHVO",
113 .irqs = tahvo_irqs,
114 .num_irqs = ARRAY_SIZE(tahvo_irqs),
115 .num_regs = 1,
116 .status_base = RETU_REG_IDR,
117 .mask_base = TAHVO_REG_IMR,
118 .ack_base = RETU_REG_IDR,
119};
120
121static const struct retu_data {
122 char *chip_name;
123 char *companion_name;
124 struct regmap_irq_chip *irq_chip;
125 struct mfd_cell *children;
126 int nchildren;
127} retu_data[] = {
128 [0] = {
129 .chip_name = "Retu",
130 .companion_name = "Vilma",
131 .irq_chip = &retu_irq_chip,
132 .children = retu_devs,
133 .nchildren = ARRAY_SIZE(retu_devs),
134 },
135 [1] = {
136 .chip_name = "Tahvo",
137 .companion_name = "Betty",
138 .irq_chip = &tahvo_irq_chip,
139 .children = tahvo_devs,
140 .nchildren = ARRAY_SIZE(tahvo_devs),
141 }
142};
143
87int retu_read(struct retu_dev *rdev, u8 reg) 144int retu_read(struct retu_dev *rdev, u8 reg)
88{ 145{
89 int ret; 146 int ret;
@@ -173,9 +230,14 @@ static struct regmap_config retu_config = {
173 230
174static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) 231static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
175{ 232{
233 struct retu_data const *rdat;
176 struct retu_dev *rdev; 234 struct retu_dev *rdev;
177 int ret; 235 int ret;
178 236
237 if (i2c->addr > ARRAY_SIZE(retu_data))
238 return -ENODEV;
239 rdat = &retu_data[i2c->addr - 1];
240
179 rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); 241 rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL);
180 if (rdev == NULL) 242 if (rdev == NULL)
181 return -ENOMEM; 243 return -ENOMEM;
@@ -190,25 +252,27 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
190 252
191 ret = retu_read(rdev, RETU_REG_ASICR); 253 ret = retu_read(rdev, RETU_REG_ASICR);
192 if (ret < 0) { 254 if (ret < 0) {
193 dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); 255 dev_err(rdev->dev, "could not read %s revision: %d\n",
256 rdat->chip_name, ret);
194 return ret; 257 return ret;
195 } 258 }
196 259
197 dev_info(rdev->dev, "Retu%s v%d.%d found\n", 260 dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name,
198 (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", 261 (ret & RETU_REG_ASICR_VILMA) ? " & " : "",
262 (ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "",
199 (ret >> 4) & 0x7, ret & 0xf); 263 (ret >> 4) & 0x7, ret & 0xf);
200 264
201 /* Mask all RETU interrupts. */ 265 /* Mask all interrupts. */
202 ret = retu_write(rdev, RETU_REG_IMR, 0xffff); 266 ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff);
203 if (ret < 0) 267 if (ret < 0)
204 return ret; 268 return ret;
205 269
206 ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, 270 ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1,
207 &retu_irq_chip, &rdev->irq_data); 271 rdat->irq_chip, &rdev->irq_data);
208 if (ret < 0) 272 if (ret < 0)
209 return ret; 273 return ret;
210 274
211 ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), 275 ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren,
212 NULL, regmap_irq_chip_get_base(rdev->irq_data), 276 NULL, regmap_irq_chip_get_base(rdev->irq_data),
213 NULL); 277 NULL);
214 if (ret < 0) { 278 if (ret < 0) {
@@ -216,7 +280,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
216 return ret; 280 return ret;
217 } 281 }
218 282
219 if (!pm_power_off) { 283 if (i2c->addr == 1 && !pm_power_off) {
220 retu_pm_power_off = rdev; 284 retu_pm_power_off = rdev;
221 pm_power_off = retu_power_off; 285 pm_power_off = retu_power_off;
222 } 286 }
@@ -240,6 +304,7 @@ static int retu_remove(struct i2c_client *i2c)
240 304
241static const struct i2c_device_id retu_id[] = { 305static const struct i2c_device_id retu_id[] = {
242 { "retu-mfd", 0 }, 306 { "retu-mfd", 0 },
307 { "tahvo-mfd", 0 },
243 { } 308 { }
244}; 309};
245MODULE_DEVICE_TABLE(i2c, retu_id); 310MODULE_DEVICE_TABLE(i2c, retu_id);