linux/drivers/mfd/88pm860x-i2c.c
<<
>>
Prefs
   1/*
   2 * I2C driver for Marvell 88PM860x
   3 *
   4 * Copyright (C) 2009 Marvell International Ltd.
   5 *      Haojian Zhuang <haojian.zhuang@marvell.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/platform_device.h>
  14#include <linux/i2c.h>
  15#include <linux/err.h>
  16#include <linux/regmap.h>
  17#include <linux/mfd/88pm860x.h>
  18#include <linux/slab.h>
  19
  20int pm860x_reg_read(struct i2c_client *i2c, int reg)
  21{
  22        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  23        struct regmap *map = (i2c == chip->client) ? chip->regmap
  24                                : chip->regmap_companion;
  25        unsigned int data;
  26        int ret;
  27
  28        ret = regmap_read(map, reg, &data);
  29        if (ret < 0)
  30                return ret;
  31        else
  32                return (int)data;
  33}
  34EXPORT_SYMBOL(pm860x_reg_read);
  35
  36int pm860x_reg_write(struct i2c_client *i2c, int reg,
  37                     unsigned char data)
  38{
  39        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  40        struct regmap *map = (i2c == chip->client) ? chip->regmap
  41                                : chip->regmap_companion;
  42        int ret;
  43
  44        ret = regmap_write(map, reg, data);
  45        return ret;
  46}
  47EXPORT_SYMBOL(pm860x_reg_write);
  48
  49int pm860x_bulk_read(struct i2c_client *i2c, int reg,
  50                     int count, unsigned char *buf)
  51{
  52        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  53        struct regmap *map = (i2c == chip->client) ? chip->regmap
  54                                : chip->regmap_companion;
  55        int ret;
  56
  57        ret = regmap_raw_read(map, reg, buf, count);
  58        return ret;
  59}
  60EXPORT_SYMBOL(pm860x_bulk_read);
  61
  62int pm860x_bulk_write(struct i2c_client *i2c, int reg,
  63                      int count, unsigned char *buf)
  64{
  65        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  66        struct regmap *map = (i2c == chip->client) ? chip->regmap
  67                                : chip->regmap_companion;
  68        int ret;
  69
  70        ret = regmap_raw_write(map, reg, buf, count);
  71        return ret;
  72}
  73EXPORT_SYMBOL(pm860x_bulk_write);
  74
  75int pm860x_set_bits(struct i2c_client *i2c, int reg,
  76                    unsigned char mask, unsigned char data)
  77{
  78        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  79        struct regmap *map = (i2c == chip->client) ? chip->regmap
  80                                : chip->regmap_companion;
  81        int ret;
  82
  83        ret = regmap_update_bits(map, reg, mask, data);
  84        return ret;
  85}
  86EXPORT_SYMBOL(pm860x_set_bits);
  87
  88static int read_device(struct i2c_client *i2c, int reg,
  89                       int bytes, void *dest)
  90{
  91        unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
  92        unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
  93        struct i2c_adapter *adap = i2c->adapter;
  94        struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
  95                                 {i2c->addr, I2C_M_RD, 0, msgbuf1},
  96                                };
  97        int num = 1, ret = 0;
  98
  99        if (dest == NULL)
 100                return -EINVAL;
 101        msgbuf0[0] = (unsigned char)reg;        /* command */
 102        msg[1].len = bytes;
 103
 104        /* if data needs to read back, num should be 2 */
 105        if (bytes > 0)
 106                num = 2;
 107        ret = adap->algo->master_xfer(adap, msg, num);
 108        memcpy(dest, msgbuf1, bytes);
 109        if (ret < 0)
 110                return ret;
 111        return 0;
 112}
 113
 114static int write_device(struct i2c_client *i2c, int reg,
 115                        int bytes, void *src)
 116{
 117        unsigned char buf[bytes + 1];
 118        struct i2c_adapter *adap = i2c->adapter;
 119        struct i2c_msg msg;
 120        int ret;
 121
 122        buf[0] = (unsigned char)reg;
 123        memcpy(&buf[1], src, bytes);
 124        msg.addr = i2c->addr;
 125        msg.flags = 0;
 126        msg.len = bytes + 1;
 127        msg.buf = buf;
 128
 129        ret = adap->algo->master_xfer(adap, &msg, 1);
 130        if (ret < 0)
 131                return ret;
 132        return 0;
 133}
 134
 135int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
 136{
 137        unsigned char zero = 0;
 138        unsigned char data;
 139        int ret;
 140
 141        i2c_lock_adapter(i2c->adapter);
 142        read_device(i2c, 0xFA, 0, &zero);
 143        read_device(i2c, 0xFB, 0, &zero);
 144        read_device(i2c, 0xFF, 0, &zero);
 145        ret = read_device(i2c, reg, 1, &data);
 146        if (ret >= 0)
 147                ret = (int)data;
 148        read_device(i2c, 0xFE, 0, &zero);
 149        read_device(i2c, 0xFC, 0, &zero);
 150        i2c_unlock_adapter(i2c->adapter);
 151        return ret;
 152}
 153EXPORT_SYMBOL(pm860x_page_reg_read);
 154
 155int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
 156                          unsigned char data)
 157{
 158        unsigned char zero;
 159        int ret;
 160
 161        i2c_lock_adapter(i2c->adapter);
 162        read_device(i2c, 0xFA, 0, &zero);
 163        read_device(i2c, 0xFB, 0, &zero);
 164        read_device(i2c, 0xFF, 0, &zero);
 165        ret = write_device(i2c, reg, 1, &data);
 166        read_device(i2c, 0xFE, 0, &zero);
 167        read_device(i2c, 0xFC, 0, &zero);
 168        i2c_unlock_adapter(i2c->adapter);
 169        return ret;
 170}
 171EXPORT_SYMBOL(pm860x_page_reg_write);
 172
 173int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
 174                          int count, unsigned char *buf)
 175{
 176        unsigned char zero = 0;
 177        int ret;
 178
 179        i2c_lock_adapter(i2c->adapter);
 180        read_device(i2c, 0xfa, 0, &zero);
 181        read_device(i2c, 0xfb, 0, &zero);
 182        read_device(i2c, 0xff, 0, &zero);
 183        ret = read_device(i2c, reg, count, buf);
 184        read_device(i2c, 0xFE, 0, &zero);
 185        read_device(i2c, 0xFC, 0, &zero);
 186        i2c_unlock_adapter(i2c->adapter);
 187        return ret;
 188}
 189EXPORT_SYMBOL(pm860x_page_bulk_read);
 190
 191int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
 192                           int count, unsigned char *buf)
 193{
 194        unsigned char zero = 0;
 195        int ret;
 196
 197        i2c_lock_adapter(i2c->adapter);
 198        read_device(i2c, 0xFA, 0, &zero);
 199        read_device(i2c, 0xFB, 0, &zero);
 200        read_device(i2c, 0xFF, 0, &zero);
 201        ret = write_device(i2c, reg, count, buf);
 202        read_device(i2c, 0xFE, 0, &zero);
 203        read_device(i2c, 0xFC, 0, &zero);
 204        i2c_unlock_adapter(i2c->adapter);
 205        i2c_unlock_adapter(i2c->adapter);
 206        return ret;
 207}
 208EXPORT_SYMBOL(pm860x_page_bulk_write);
 209
 210int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
 211                         unsigned char mask, unsigned char data)
 212{
 213        unsigned char zero;
 214        unsigned char value;
 215        int ret;
 216
 217        i2c_lock_adapter(i2c->adapter);
 218        read_device(i2c, 0xFA, 0, &zero);
 219        read_device(i2c, 0xFB, 0, &zero);
 220        read_device(i2c, 0xFF, 0, &zero);
 221        ret = read_device(i2c, reg, 1, &value);
 222        if (ret < 0)
 223                goto out;
 224        value &= ~mask;
 225        value |= data;
 226        ret = write_device(i2c, reg, 1, &value);
 227out:
 228        read_device(i2c, 0xFE, 0, &zero);
 229        read_device(i2c, 0xFC, 0, &zero);
 230        i2c_unlock_adapter(i2c->adapter);
 231        return ret;
 232}
 233EXPORT_SYMBOL(pm860x_page_set_bits);
 234
 235static const struct i2c_device_id pm860x_id_table[] = {
 236        { "88PM860x", 0 },
 237        {}
 238};
 239MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
 240
 241static int verify_addr(struct i2c_client *i2c)
 242{
 243        unsigned short addr_8607[] = {0x30, 0x34};
 244        unsigned short addr_8606[] = {0x10, 0x11};
 245        int size, i;
 246
 247        if (i2c == NULL)
 248                return 0;
 249        size = ARRAY_SIZE(addr_8606);
 250        for (i = 0; i < size; i++) {
 251                if (i2c->addr == *(addr_8606 + i))
 252                        return CHIP_PM8606;
 253        }
 254        size = ARRAY_SIZE(addr_8607);
 255        for (i = 0; i < size; i++) {
 256                if (i2c->addr == *(addr_8607 + i))
 257                        return CHIP_PM8607;
 258        }
 259        return 0;
 260}
 261
 262static struct regmap_config pm860x_regmap_config = {
 263        .reg_bits = 8,
 264        .val_bits = 8,
 265};
 266
 267static int __devinit pm860x_probe(struct i2c_client *client,
 268                                  const struct i2c_device_id *id)
 269{
 270        struct pm860x_platform_data *pdata = client->dev.platform_data;
 271        struct pm860x_chip *chip;
 272        int ret;
 273
 274        if (!pdata) {
 275                pr_info("No platform data in %s!\n", __func__);
 276                return -EINVAL;
 277        }
 278
 279        chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
 280        if (chip == NULL)
 281                return -ENOMEM;
 282
 283        chip->id = verify_addr(client);
 284        chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
 285        if (IS_ERR(chip->regmap)) {
 286                ret = PTR_ERR(chip->regmap);
 287                dev_err(&client->dev, "Failed to allocate register map: %d\n",
 288                                ret);
 289                kfree(chip);
 290                return ret;
 291        }
 292        chip->client = client;
 293        i2c_set_clientdata(client, chip);
 294        chip->dev = &client->dev;
 295        dev_set_drvdata(chip->dev, chip);
 296
 297        /*
 298         * Both client and companion client shares same platform driver.
 299         * Driver distinguishes them by pdata->companion_addr.
 300         * pdata->companion_addr is only assigned if companion chip exists.
 301         * At the same time, the companion_addr shouldn't equal to client
 302         * address.
 303         */
 304        if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {
 305                chip->companion_addr = pdata->companion_addr;
 306                chip->companion = i2c_new_dummy(chip->client->adapter,
 307                                                chip->companion_addr);
 308                chip->regmap_companion = regmap_init_i2c(chip->companion,
 309                                                        &pm860x_regmap_config);
 310                if (IS_ERR(chip->regmap_companion)) {
 311                        ret = PTR_ERR(chip->regmap_companion);
 312                        dev_err(&chip->companion->dev,
 313                                "Failed to allocate register map: %d\n", ret);
 314                        return ret;
 315                }
 316                i2c_set_clientdata(chip->companion, chip);
 317        }
 318
 319        pm860x_device_init(chip, pdata);
 320        return 0;
 321}
 322
 323static int __devexit pm860x_remove(struct i2c_client *client)
 324{
 325        struct pm860x_chip *chip = i2c_get_clientdata(client);
 326
 327        pm860x_device_exit(chip);
 328        if (chip->companion) {
 329                regmap_exit(chip->regmap_companion);
 330                i2c_unregister_device(chip->companion);
 331        }
 332        regmap_exit(chip->regmap);
 333        kfree(chip);
 334        return 0;
 335}
 336
 337#ifdef CONFIG_PM_SLEEP
 338static int pm860x_suspend(struct device *dev)
 339{
 340        struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 341        struct pm860x_chip *chip = i2c_get_clientdata(client);
 342
 343        if (device_may_wakeup(dev) && chip->wakeup_flag)
 344                enable_irq_wake(chip->core_irq);
 345        return 0;
 346}
 347
 348static int pm860x_resume(struct device *dev)
 349{
 350        struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 351        struct pm860x_chip *chip = i2c_get_clientdata(client);
 352
 353        if (device_may_wakeup(dev) && chip->wakeup_flag)
 354                disable_irq_wake(chip->core_irq);
 355        return 0;
 356}
 357#endif
 358
 359static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
 360
 361static struct i2c_driver pm860x_driver = {
 362        .driver = {
 363                .name   = "88PM860x",
 364                .owner  = THIS_MODULE,
 365                .pm     = &pm860x_pm_ops,
 366        },
 367        .probe          = pm860x_probe,
 368        .remove         = __devexit_p(pm860x_remove),
 369        .id_table       = pm860x_id_table,
 370};
 371
 372static int __init pm860x_i2c_init(void)
 373{
 374        int ret;
 375        ret = i2c_add_driver(&pm860x_driver);
 376        if (ret != 0)
 377                pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
 378        return ret;
 379}
 380subsys_initcall(pm860x_i2c_init);
 381
 382static void __exit pm860x_i2c_exit(void)
 383{
 384        i2c_del_driver(&pm860x_driver);
 385}
 386module_exit(pm860x_i2c_exit);
 387
 388MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
 389MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 390MODULE_LICENSE("GPL");
 391
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.