linux/drivers/mfd/pcf50633-core.c
<<
>>
Prefs
   1/* NXP PCF50633 Power Management Unit (PMU) driver
   2 *
   3 * (C) 2006-2008 by Openmoko, Inc.
   4 * Author: Harald Welte <laforge@openmoko.org>
   5 *         Balaji Rao <balajirrao@openmoko.org>
   6 * All rights reserved.
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 *
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/device.h>
  17#include <linux/sysfs.h>
  18#include <linux/module.h>
  19#include <linux/types.h>
  20#include <linux/interrupt.h>
  21#include <linux/workqueue.h>
  22#include <linux/platform_device.h>
  23#include <linux/i2c.h>
  24#include <linux/pm.h>
  25#include <linux/slab.h>
  26
  27#include <linux/mfd/pcf50633/core.h>
  28
  29static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
  30{
  31        int ret;
  32
  33        ret = i2c_smbus_read_i2c_block_data(pcf->i2c_client, reg,
  34                                num, data);
  35        if (ret < 0)
  36                dev_err(pcf->dev, "Error reading %d regs at %d\n", num, reg);
  37
  38        return ret;
  39}
  40
  41static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
  42{
  43        int ret;
  44
  45        ret = i2c_smbus_write_i2c_block_data(pcf->i2c_client, reg,
  46                                num, data);
  47        if (ret < 0)
  48                dev_err(pcf->dev, "Error writing %d regs at %d\n", num, reg);
  49
  50        return ret;
  51
  52}
  53
  54/* Read a block of up to 32 regs  */
  55int pcf50633_read_block(struct pcf50633 *pcf, u8 reg,
  56                                        int nr_regs, u8 *data)
  57{
  58        int ret;
  59
  60        mutex_lock(&pcf->lock);
  61        ret = __pcf50633_read(pcf, reg, nr_regs, data);
  62        mutex_unlock(&pcf->lock);
  63
  64        return ret;
  65}
  66EXPORT_SYMBOL_GPL(pcf50633_read_block);
  67
  68/* Write a block of up to 32 regs  */
  69int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
  70                                        int nr_regs, u8 *data)
  71{
  72        int ret;
  73
  74        mutex_lock(&pcf->lock);
  75        ret = __pcf50633_write(pcf, reg, nr_regs, data);
  76        mutex_unlock(&pcf->lock);
  77
  78        return ret;
  79}
  80EXPORT_SYMBOL_GPL(pcf50633_write_block);
  81
  82u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg)
  83{
  84        u8 val;
  85
  86        mutex_lock(&pcf->lock);
  87        __pcf50633_read(pcf, reg, 1, &val);
  88        mutex_unlock(&pcf->lock);
  89
  90        return val;
  91}
  92EXPORT_SYMBOL_GPL(pcf50633_reg_read);
  93
  94int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val)
  95{
  96        int ret;
  97
  98        mutex_lock(&pcf->lock);
  99        ret = __pcf50633_write(pcf, reg, 1, &val);
 100        mutex_unlock(&pcf->lock);
 101
 102        return ret;
 103}
 104EXPORT_SYMBOL_GPL(pcf50633_reg_write);
 105
 106int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val)
 107{
 108        int ret;
 109        u8 tmp;
 110
 111        val &= mask;
 112
 113        mutex_lock(&pcf->lock);
 114        ret = __pcf50633_read(pcf, reg, 1, &tmp);
 115        if (ret < 0)
 116                goto out;
 117
 118        tmp &= ~mask;
 119        tmp |= val;
 120        ret = __pcf50633_write(pcf, reg, 1, &tmp);
 121
 122out:
 123        mutex_unlock(&pcf->lock);
 124
 125        return ret;
 126}
 127EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask);
 128
 129int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val)
 130{
 131        int ret;
 132        u8 tmp;
 133
 134        mutex_lock(&pcf->lock);
 135        ret = __pcf50633_read(pcf, reg, 1, &tmp);
 136        if (ret < 0)
 137                goto out;
 138
 139        tmp &= ~val;
 140        ret = __pcf50633_write(pcf, reg, 1, &tmp);
 141
 142out:
 143        mutex_unlock(&pcf->lock);
 144
 145        return ret;
 146}
 147EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits);
 148
 149/* sysfs attributes */
 150static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
 151                            char *buf)
 152{
 153        struct pcf50633 *pcf = dev_get_drvdata(dev);
 154        u8 dump[16];
 155        int n, n1, idx = 0;
 156        char *buf1 = buf;
 157        static u8 address_no_read[] = { /* must be ascending */
 158                PCF50633_REG_INT1,
 159                PCF50633_REG_INT2,
 160                PCF50633_REG_INT3,
 161                PCF50633_REG_INT4,
 162                PCF50633_REG_INT5,
 163                0 /* terminator */
 164        };
 165
 166        for (n = 0; n < 256; n += sizeof(dump)) {
 167                for (n1 = 0; n1 < sizeof(dump); n1++)
 168                        if (n == address_no_read[idx]) {
 169                                idx++;
 170                                dump[n1] = 0x00;
 171                        } else
 172                                dump[n1] = pcf50633_reg_read(pcf, n + n1);
 173
 174                hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0);
 175                buf1 += strlen(buf1);
 176                *buf1++ = '\n';
 177                *buf1 = '\0';
 178        }
 179
 180        return buf1 - buf;
 181}
 182static DEVICE_ATTR(dump_regs, 0400, show_dump_regs, NULL);
 183
 184static ssize_t show_resume_reason(struct device *dev,
 185                                struct device_attribute *attr, char *buf)
 186{
 187        struct pcf50633 *pcf = dev_get_drvdata(dev);
 188        int n;
 189
 190        n = sprintf(buf, "%02x%02x%02x%02x%02x\n",
 191                                pcf->resume_reason[0],
 192                                pcf->resume_reason[1],
 193                                pcf->resume_reason[2],
 194                                pcf->resume_reason[3],
 195                                pcf->resume_reason[4]);
 196
 197        return n;
 198}
 199static DEVICE_ATTR(resume_reason, 0400, show_resume_reason, NULL);
 200
 201static struct attribute *pcf_sysfs_entries[] = {
 202        &dev_attr_dump_regs.attr,
 203        &dev_attr_resume_reason.attr,
 204        NULL,
 205};
 206
 207static struct attribute_group pcf_attr_group = {
 208        .name   = NULL,                 /* put in device directory */
 209        .attrs  = pcf_sysfs_entries,
 210};
 211
 212static void
 213pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
 214                                                struct platform_device **pdev)
 215{
 216        int ret;
 217
 218        *pdev = platform_device_alloc(name, -1);
 219        if (!*pdev) {
 220                dev_err(pcf->dev, "Falied to allocate %s\n", name);
 221                return;
 222        }
 223
 224        (*pdev)->dev.parent = pcf->dev;
 225
 226        ret = platform_device_add(*pdev);
 227        if (ret) {
 228                dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret);
 229                platform_device_put(*pdev);
 230                *pdev = NULL;
 231        }
 232}
 233
 234#ifdef CONFIG_PM_SLEEP
 235static int pcf50633_suspend(struct device *dev)
 236{
 237        struct i2c_client *client = to_i2c_client(dev);
 238        struct pcf50633 *pcf = i2c_get_clientdata(client);
 239
 240        return pcf50633_irq_suspend(pcf);
 241}
 242
 243static int pcf50633_resume(struct device *dev)
 244{
 245        struct i2c_client *client = to_i2c_client(dev);
 246        struct pcf50633 *pcf = i2c_get_clientdata(client);
 247
 248        return pcf50633_irq_resume(pcf);
 249}
 250#endif
 251
 252static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
 253
 254static int __devinit pcf50633_probe(struct i2c_client *client,
 255                                const struct i2c_device_id *ids)
 256{
 257        struct pcf50633 *pcf;
 258        struct pcf50633_platform_data *pdata = client->dev.platform_data;
 259        int i, ret;
 260        int version, variant;
 261
 262        if (!client->irq) {
 263                dev_err(&client->dev, "Missing IRQ\n");
 264                return -ENOENT;
 265        }
 266
 267        pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
 268        if (!pcf)
 269                return -ENOMEM;
 270
 271        pcf->pdata = pdata;
 272
 273        mutex_init(&pcf->lock);
 274
 275        i2c_set_clientdata(client, pcf);
 276        pcf->dev = &client->dev;
 277        pcf->i2c_client = client;
 278
 279        version = pcf50633_reg_read(pcf, 0);
 280        variant = pcf50633_reg_read(pcf, 1);
 281        if (version < 0 || variant < 0) {
 282                dev_err(pcf->dev, "Unable to probe pcf50633\n");
 283                ret = -ENODEV;
 284                goto err_free;
 285        }
 286
 287        dev_info(pcf->dev, "Probed device version %d variant %d\n",
 288                                                        version, variant);
 289
 290        pcf50633_irq_init(pcf, client->irq);
 291
 292        /* Create sub devices */
 293        pcf50633_client_dev_register(pcf, "pcf50633-input",
 294                                                &pcf->input_pdev);
 295        pcf50633_client_dev_register(pcf, "pcf50633-rtc",
 296                                                &pcf->rtc_pdev);
 297        pcf50633_client_dev_register(pcf, "pcf50633-mbc",
 298                                                &pcf->mbc_pdev);
 299        pcf50633_client_dev_register(pcf, "pcf50633-adc",
 300                                                &pcf->adc_pdev);
 301        pcf50633_client_dev_register(pcf, "pcf50633-backlight",
 302                                                &pcf->bl_pdev);
 303
 304
 305        for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
 306                struct platform_device *pdev;
 307
 308                pdev = platform_device_alloc("pcf50633-regltr", i);
 309                if (!pdev) {
 310                        dev_err(pcf->dev, "Cannot create regulator %d\n", i);
 311                        continue;
 312                }
 313
 314                pdev->dev.parent = pcf->dev;
 315                platform_device_add_data(pdev, &pdata->reg_init_data[i],
 316                                        sizeof(pdata->reg_init_data[i]));
 317                pcf->regulator_pdev[i] = pdev;
 318
 319                platform_device_add(pdev);
 320        }
 321
 322        ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
 323        if (ret)
 324                dev_err(pcf->dev, "error creating sysfs entries\n");
 325
 326        if (pdata->probe_done)
 327                pdata->probe_done(pcf);
 328
 329        return 0;
 330
 331err_free:
 332        kfree(pcf);
 333
 334        return ret;
 335}
 336
 337static int __devexit pcf50633_remove(struct i2c_client *client)
 338{
 339        struct pcf50633 *pcf = i2c_get_clientdata(client);
 340        int i;
 341
 342        sysfs_remove_group(&client->dev.kobj, &pcf_attr_group);
 343        pcf50633_irq_free(pcf);
 344
 345        platform_device_unregister(pcf->input_pdev);
 346        platform_device_unregister(pcf->rtc_pdev);
 347        platform_device_unregister(pcf->mbc_pdev);
 348        platform_device_unregister(pcf->adc_pdev);
 349        platform_device_unregister(pcf->bl_pdev);
 350
 351        for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
 352                platform_device_unregister(pcf->regulator_pdev[i]);
 353
 354        kfree(pcf);
 355
 356        return 0;
 357}
 358
 359static const struct i2c_device_id pcf50633_id_table[] = {
 360        {"pcf50633", 0x73},
 361        {/* end of list */}
 362};
 363MODULE_DEVICE_TABLE(i2c, pcf50633_id_table);
 364
 365static struct i2c_driver pcf50633_driver = {
 366        .driver = {
 367                .name   = "pcf50633",
 368                .pm     = &pcf50633_pm,
 369        },
 370        .id_table = pcf50633_id_table,
 371        .probe = pcf50633_probe,
 372        .remove = __devexit_p(pcf50633_remove),
 373};
 374
 375static int __init pcf50633_init(void)
 376{
 377        return i2c_add_driver(&pcf50633_driver);
 378}
 379
 380static void __exit pcf50633_exit(void)
 381{
 382        i2c_del_driver(&pcf50633_driver);
 383}
 384
 385MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU");
 386MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
 387MODULE_LICENSE("GPL");
 388
 389subsys_initcall(pcf50633_init);
 390module_exit(pcf50633_exit);
 391