1 /* 2 * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs 3 * LCD Backlight: drivers/video/backlight/adp5520_bl 4 * LEDs : drivers/led/leds-adp5520 5 * GPIO : drivers/gpio/adp5520-gpio (ADP5520 only) 6 * Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only) 7 * 8 * Copyright 2009 Analog Devices Inc. 9 * 10 * Derived from da903x: 11 * Copyright (C) 2008 Compulab, Ltd. 12 * Mike Rapoport <mike@compulab.co.il> 13 * 14 * Copyright (C) 2006-2008 Marvell International Ltd. 15 * Eric Miao <eric.miao@marvell.com> 16 * 17 * Licensed under the GPL-2 or later. 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/platform_device.h> 23 #include <linux/init.h> 24 #include <linux/slab.h> 25 #include <linux/interrupt.h> 26 #include <linux/irq.h> 27 #include <linux/err.h> 28 #include <linux/i2c.h> 29 30 #include <linux/mfd/adp5520.h> 31 32 struct adp5520_chip { 33 struct i2c_client *client; 34 struct device *dev; 35 struct mutex lock; 36 struct blocking_notifier_head notifier_list; 37 int irq; 38 unsigned long id; 39 uint8_t mode; 40 }; 41 42 static int __adp5520_read(struct i2c_client *client, 43 int reg, uint8_t *val) 44 { 45 int ret; 46 47 ret = i2c_smbus_read_byte_data(client, reg); 48 if (ret < 0) { 49 dev_err(&client->dev, "failed reading at 0x%02x\n", reg); 50 return ret; 51 } 52 53 *val = (uint8_t)ret; 54 return 0; 55 } 56 57 static int __adp5520_write(struct i2c_client *client, 58 int reg, uint8_t val) 59 { 60 int ret; 61 62 ret = i2c_smbus_write_byte_data(client, reg, val); 63 if (ret < 0) { 64 dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", 65 val, reg); 66 return ret; 67 } 68 return 0; 69 } 70 71 static int __adp5520_ack_bits(struct i2c_client *client, int reg, 72 uint8_t bit_mask) 73 { 74 struct adp5520_chip *chip = i2c_get_clientdata(client); 75 uint8_t reg_val; 76 int ret; 77 78 mutex_lock(&chip->lock); 79 80 ret = __adp5520_read(client, reg, ®_val); 81 82 if (!ret) { 83 reg_val |= bit_mask; 84 ret = __adp5520_write(client, reg, reg_val); 85 } 86 87 mutex_unlock(&chip->lock); 88 return ret; 89 } 90 91 int adp5520_write(struct device *dev, int reg, uint8_t val) 92 { 93 return __adp5520_write(to_i2c_client(dev), reg, val); 94 } 95 EXPORT_SYMBOL_GPL(adp5520_write); 96 97 int adp5520_read(struct device *dev, int reg, uint8_t *val) 98 { 99 return __adp5520_read(to_i2c_client(dev), reg, val); 100 } 101 EXPORT_SYMBOL_GPL(adp5520_read); 102 103 int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask) 104 { 105 struct adp5520_chip *chip = dev_get_drvdata(dev); 106 uint8_t reg_val; 107 int ret; 108 109 mutex_lock(&chip->lock); 110 111 ret = __adp5520_read(chip->client, reg, ®_val); 112 113 if (!ret && ((reg_val & bit_mask) != bit_mask)) { 114 reg_val |= bit_mask; 115 ret = __adp5520_write(chip->client, reg, reg_val); 116 } 117 118 mutex_unlock(&chip->lock); 119 return ret; 120 } 121 EXPORT_SYMBOL_GPL(adp5520_set_bits); 122 123 int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask) 124 { 125 struct adp5520_chip *chip = dev_get_drvdata(dev); 126 uint8_t reg_val; 127 int ret; 128 129 mutex_lock(&chip->lock); 130 131 ret = __adp5520_read(chip->client, reg, ®_val); 132 133 if (!ret && (reg_val & bit_mask)) { 134 reg_val &= ~bit_mask; 135 ret = __adp5520_write(chip->client, reg, reg_val); 136 } 137 138 mutex_unlock(&chip->lock); 139 return ret; 140 } 141 EXPORT_SYMBOL_GPL(adp5520_clr_bits); 142 143 int adp5520_register_notifier(struct device *dev, struct notifier_block *nb, 144 unsigned int events) 145 { 146 struct adp5520_chip *chip = dev_get_drvdata(dev); 147 148 if (chip->irq) { 149 adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, 150 events & (ADP5520_KP_IEN | ADP5520_KR_IEN | 151 ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); 152 153 return blocking_notifier_chain_register(&chip->notifier_list, 154 nb); 155 } 156 157 return -ENODEV; 158 } 159 EXPORT_SYMBOL_GPL(adp5520_register_notifier); 160 161 int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb, 162 unsigned int events) 163 { 164 struct adp5520_chip *chip = dev_get_drvdata(dev); 165 166 adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, 167 events & (ADP5520_KP_IEN | ADP5520_KR_IEN | 168 ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); 169 170 return blocking_notifier_chain_unregister(&chip->notifier_list, nb); 171 } 172 EXPORT_SYMBOL_GPL(adp5520_unregister_notifier); 173 174 static irqreturn_t adp5520_irq_thread(int irq, void *data) 175 { 176 struct adp5520_chip *chip = data; 177 unsigned int events; 178 uint8_t reg_val; 179 int ret; 180 181 ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, ®_val); 182 if (ret) 183 goto out; 184 185 events = reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT | 186 ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT); 187 188 blocking_notifier_call_chain(&chip->notifier_list, events, NULL); 189 /* ACK, Sticky bits are W1C */ 190 __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events); 191 192 out: 193 return IRQ_HANDLED; 194 } 195 196 static int __remove_subdev(struct device *dev, void *unused) 197 { 198 platform_device_unregister(to_platform_device(dev)); 199 return 0; 200 } 201 202 static int adp5520_remove_subdevs(struct adp5520_chip *chip) 203 { 204 return device_for_each_child(chip->dev, NULL, __remove_subdev); 205 } 206 207 static int adp5520_probe(struct i2c_client *client, 208 const struct i2c_device_id *id) 209 { 210 struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev); 211 struct platform_device *pdev; 212 struct adp5520_chip *chip; 213 int ret; 214 215 if (!i2c_check_functionality(client->adapter, 216 I2C_FUNC_SMBUS_BYTE_DATA)) { 217 dev_err(&client->dev, "SMBUS Word Data not Supported\n"); 218 return -EIO; 219 } 220 221 if (pdata == NULL) { 222 dev_err(&client->dev, "missing platform data\n"); 223 return -ENODEV; 224 } 225 226 chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 227 if (!chip) 228 return -ENOMEM; 229 230 i2c_set_clientdata(client, chip); 231 chip->client = client; 232 233 chip->dev = &client->dev; 234 chip->irq = client->irq; 235 chip->id = id->driver_data; 236 mutex_init(&chip->lock); 237 238 if (chip->irq) { 239 BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); 240 241 ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread, 242 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 243 "adp5520", chip); 244 if (ret) { 245 dev_err(&client->dev, "failed to request irq %d\n", 246 chip->irq); 247 return ret; 248 } 249 } 250 251 ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); 252 if (ret) { 253 dev_err(&client->dev, "failed to write\n"); 254 goto out_free_irq; 255 } 256 257 if (pdata->keys) { 258 pdev = platform_device_register_data(chip->dev, "adp5520-keys", 259 chip->id, pdata->keys, sizeof(*pdata->keys)); 260 if (IS_ERR(pdev)) { 261 ret = PTR_ERR(pdev); 262 goto out_remove_subdevs; 263 } 264 } 265 266 if (pdata->gpio) { 267 pdev = platform_device_register_data(chip->dev, "adp5520-gpio", 268 chip->id, pdata->gpio, sizeof(*pdata->gpio)); 269 if (IS_ERR(pdev)) { 270 ret = PTR_ERR(pdev); 271 goto out_remove_subdevs; 272 } 273 } 274 275 if (pdata->leds) { 276 pdev = platform_device_register_data(chip->dev, "adp5520-led", 277 chip->id, pdata->leds, sizeof(*pdata->leds)); 278 if (IS_ERR(pdev)) { 279 ret = PTR_ERR(pdev); 280 goto out_remove_subdevs; 281 } 282 } 283 284 if (pdata->backlight) { 285 pdev = platform_device_register_data(chip->dev, 286 "adp5520-backlight", 287 chip->id, 288 pdata->backlight, 289 sizeof(*pdata->backlight)); 290 if (IS_ERR(pdev)) { 291 ret = PTR_ERR(pdev); 292 goto out_remove_subdevs; 293 } 294 } 295 296 return 0; 297 298 out_remove_subdevs: 299 adp5520_remove_subdevs(chip); 300 301 out_free_irq: 302 if (chip->irq) 303 free_irq(chip->irq, chip); 304 305 return ret; 306 } 307 308 static int adp5520_remove(struct i2c_client *client) 309 { 310 struct adp5520_chip *chip = dev_get_drvdata(&client->dev); 311 312 if (chip->irq) 313 free_irq(chip->irq, chip); 314 315 adp5520_remove_subdevs(chip); 316 adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); 317 return 0; 318 } 319 320 #ifdef CONFIG_PM_SLEEP 321 static int adp5520_suspend(struct device *dev) 322 { 323 struct i2c_client *client = to_i2c_client(dev); 324 struct adp5520_chip *chip = dev_get_drvdata(&client->dev); 325 326 adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode); 327 /* All other bits are W1C */ 328 chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY; 329 adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); 330 return 0; 331 } 332 333 static int adp5520_resume(struct device *dev) 334 { 335 struct i2c_client *client = to_i2c_client(dev); 336 struct adp5520_chip *chip = dev_get_drvdata(&client->dev); 337 338 adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode); 339 return 0; 340 } 341 #endif 342 343 static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume); 344 345 static const struct i2c_device_id adp5520_id[] = { 346 { "pmic-adp5520", ID_ADP5520 }, 347 { "pmic-adp5501", ID_ADP5501 }, 348 { } 349 }; 350 MODULE_DEVICE_TABLE(i2c, adp5520_id); 351 352 static struct i2c_driver adp5520_driver = { 353 .driver = { 354 .name = "adp5520", 355 .owner = THIS_MODULE, 356 .pm = &adp5520_pm, 357 }, 358 .probe = adp5520_probe, 359 .remove = adp5520_remove, 360 .id_table = adp5520_id, 361 }; 362 363 module_i2c_driver(adp5520_driver); 364 365 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 366 MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); 367 MODULE_LICENSE("GPL"); 368