Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Aaro Koskinen and committed by
Samuel Ortiz
95e50f6a 360e64d8

+85 -14
+3 -3
drivers/mfd/Kconfig
··· 371 371 The drivers do not support all features the board exposes. 372 372 373 373 config MFD_RETU 374 - tristate "Nokia Retu multi-function device" 374 + tristate "Nokia Retu and Tahvo multi-function device" 375 375 select MFD_CORE 376 376 depends on I2C && GENERIC_HARDIRQS 377 377 select REGMAP_IRQ 378 378 help 379 - Retu is a multi-function device found on Nokia Internet Tablets 380 - (770, N800 and N810). 379 + Retu and Tahvo are a multi-function devices found on Nokia 380 + Internet Tablets (770, N800 and N810). 381 381 382 382 config MFD_PCF50633 383 383 tristate "NXP PCF50633"
+75 -10
drivers/mfd/retu-mfd.c
··· 1 1 /* 2 - * Retu MFD driver 2 + * Retu/Tahvo MFD driver 3 3 * 4 4 * Copyright (C) 2004, 2005 Nokia Corporation 5 5 * ··· 33 33 #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ 34 34 #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ 35 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 39 /* Interrupt sources */ 39 40 #define RETU_INT_PWR 0 /* Power button */ ··· 84 83 85 84 /* Retu device registered for the power off. */ 86 85 static struct retu_dev *retu_pm_power_off; 86 + 87 + static struct resource tahvo_usb_res[] = { 88 + { 89 + .name = "tahvo-usb", 90 + .start = TAHVO_INT_VBUS, 91 + .end = TAHVO_INT_VBUS, 92 + .flags = IORESOURCE_IRQ, 93 + }, 94 + }; 95 + 96 + static struct mfd_cell tahvo_devs[] = { 97 + { 98 + .name = "tahvo-usb", 99 + .resources = tahvo_usb_res, 100 + .num_resources = ARRAY_SIZE(tahvo_usb_res), 101 + }, 102 + }; 103 + 104 + static struct regmap_irq tahvo_irqs[] = { 105 + [TAHVO_INT_VBUS] = { 106 + .mask = 1 << TAHVO_INT_VBUS, 107 + } 108 + }; 109 + 110 + static struct regmap_irq_chip tahvo_irq_chip = { 111 + .name = "TAHVO", 112 + .irqs = tahvo_irqs, 113 + .num_irqs = ARRAY_SIZE(tahvo_irqs), 114 + .num_regs = 1, 115 + .status_base = RETU_REG_IDR, 116 + .mask_base = TAHVO_REG_IMR, 117 + .ack_base = RETU_REG_IDR, 118 + }; 119 + 120 + static const struct retu_data { 121 + char *chip_name; 122 + char *companion_name; 123 + struct regmap_irq_chip *irq_chip; 124 + struct mfd_cell *children; 125 + int nchildren; 126 + } retu_data[] = { 127 + [0] = { 128 + .chip_name = "Retu", 129 + .companion_name = "Vilma", 130 + .irq_chip = &retu_irq_chip, 131 + .children = retu_devs, 132 + .nchildren = ARRAY_SIZE(retu_devs), 133 + }, 134 + [1] = { 135 + .chip_name = "Tahvo", 136 + .companion_name = "Betty", 137 + .irq_chip = &tahvo_irq_chip, 138 + .children = tahvo_devs, 139 + .nchildren = ARRAY_SIZE(tahvo_devs), 140 + } 141 + }; 87 142 88 143 int retu_read(struct retu_dev *rdev, u8 reg) 89 144 { ··· 230 173 231 174 static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) 232 175 { 176 + struct retu_data const *rdat; 233 177 struct retu_dev *rdev; 234 178 int ret; 179 + 180 + if (i2c->addr > ARRAY_SIZE(retu_data)) 181 + return -ENODEV; 182 + rdat = &retu_data[i2c->addr - 1]; 235 183 236 184 rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); 237 185 if (rdev == NULL) ··· 252 190 253 191 ret = retu_read(rdev, RETU_REG_ASICR); 254 192 if (ret < 0) { 255 - dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); 193 + dev_err(rdev->dev, "could not read %s revision: %d\n", 194 + rdat->chip_name, ret); 256 195 return ret; 257 196 } 258 197 259 - dev_info(rdev->dev, "Retu%s v%d.%d found\n", 260 - (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", 198 + dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name, 199 + (ret & RETU_REG_ASICR_VILMA) ? " & " : "", 200 + (ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "", 261 201 (ret >> 4) & 0x7, ret & 0xf); 262 202 263 - /* Mask all RETU interrupts. */ 264 - ret = retu_write(rdev, RETU_REG_IMR, 0xffff); 203 + /* Mask all interrupts. */ 204 + ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff); 265 205 if (ret < 0) 266 206 return ret; 267 207 268 208 ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, 269 - &retu_irq_chip, &rdev->irq_data); 209 + rdat->irq_chip, &rdev->irq_data); 270 210 if (ret < 0) 271 211 return ret; 272 212 273 - ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), 213 + ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren, 274 214 NULL, regmap_irq_chip_get_base(rdev->irq_data), 275 215 NULL); 276 216 if (ret < 0) { ··· 280 216 return ret; 281 217 } 282 218 283 - if (!pm_power_off) { 219 + if (i2c->addr == 1 && !pm_power_off) { 284 220 retu_pm_power_off = rdev; 285 221 pm_power_off = retu_power_off; 286 222 } ··· 304 240 305 241 static const struct i2c_device_id retu_id[] = { 306 242 { "retu-mfd", 0 }, 243 + { "tahvo-mfd", 0 }, 307 244 { } 308 245 }; 309 246 MODULE_DEVICE_TABLE(i2c, retu_id);
+7 -1
include/linux/mfd/retu.h
··· 1 1 /* 2 - * Retu MFD driver interface 2 + * Retu/Tahvo MFD driver interface 3 3 * 4 4 * This file is subject to the terms and conditions of the GNU General 5 5 * Public License. See the file "COPYING" in the main directory of this ··· 18 18 #define RETU_REG_WATCHDOG 0x17 /* Watchdog */ 19 19 #define RETU_REG_CC1 0x0d /* Common control register 1 */ 20 20 #define RETU_REG_STATUS 0x16 /* Status register */ 21 + 22 + /* Interrupt sources */ 23 + #define TAHVO_INT_VBUS 0 /* VBUS state */ 24 + 25 + /* Interrupt status */ 26 + #define TAHVO_STAT_VBUS (1 << TAHVO_INT_VBUS) 21 27 22 28 #endif /* __LINUX_MFD_RETU_H */