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/i2c.h>
  14#include <linux/regmap.h>
  15#include <linux/mfd/88pm860x.h>
  16
  17int pm860x_reg_read(struct i2c_client *i2c, int reg)
  18{
  19        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  20        struct regmap *map = (i2c == chip->client) ? chip->regmap
  21                                : chip->regmap_companion;
  22        unsigned int data;
  23        int ret;
  24
  25        ret = regmap_read(map, reg, &data);
  26        if (ret < 0)
  27                return ret;
  28        else
  29                return (int)data;
  30}
  31EXPORT_SYMBOL(pm860x_reg_read);
  32
  33int pm860x_reg_write(struct i2c_client *i2c, int reg,
  34                     unsigned char data)
  35{
  36        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  37        struct regmap *map = (i2c == chip->client) ? chip->regmap
  38                                : chip->regmap_companion;
  39        int ret;
  40
  41        ret = regmap_write(map, reg, data);
  42        return ret;
  43}
  44EXPORT_SYMBOL(pm860x_reg_write);
  45
  46int pm860x_bulk_read(struct i2c_client *i2c, int reg,
  47                     int count, unsigned char *buf)
  48{
  49        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  50        struct regmap *map = (i2c == chip->client) ? chip->regmap
  51                                : chip->regmap_companion;
  52        int ret;
  53
  54        ret = regmap_raw_read(map, reg, buf, count);
  55        return ret;
  56}
  57EXPORT_SYMBOL(pm860x_bulk_read);
  58
  59int pm860x_bulk_write(struct i2c_client *i2c, int reg,
  60                      int count, unsigned char *buf)
  61{
  62        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  63        struct regmap *map = (i2c == chip->client) ? chip->regmap
  64                                : chip->regmap_companion;
  65        int ret;
  66
  67        ret = regmap_raw_write(map, reg, buf, count);
  68        return ret;
  69}
  70EXPORT_SYMBOL(pm860x_bulk_write);
  71
  72int pm860x_set_bits(struct i2c_client *i2c, int reg,
  73                    unsigned char mask, unsigned char data)
  74{
  75        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  76        struct regmap *map = (i2c == chip->client) ? chip->regmap
  77                                : chip->regmap_companion;
  78        int ret;
  79
  80        ret = regmap_update_bits(map, reg, mask, data);
  81        return ret;
  82}
  83EXPORT_SYMBOL(pm860x_set_bits);
  84
  85static int read_device(struct i2c_client *i2c, int reg,
  86                       int bytes, void *dest)
  87{
  88        unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
  89        unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
  90        struct i2c_adapter *adap = i2c->adapter;
  91        struct i2c_msg msg[2] = {
  92                                        {
  93                                                .addr = i2c->addr,
  94                                                .flags = 0,
  95                                                .len = 1,
  96                                                .buf = msgbuf0
  97                                        },
  98                                        {       .addr = i2c->addr,
  99                                                .flags = I2C_M_RD,
 100                                                .len = 0,
 101                                                .buf = msgbuf1
 102                                        },
 103                                };
 104        int num = 1, ret = 0;
 105
 106        if (dest == NULL)
 107                return -EINVAL;
 108        msgbuf0[0] = (unsigned char)reg;        /* command */
 109        msg[1].len = bytes;
 110
 111        /* if data needs to read back, num should be 2 */
 112        if (bytes > 0)
 113                num = 2;
 114        ret = adap->algo->master_xfer(adap, msg, num);
 115        memcpy(dest, msgbuf1, bytes);
 116        if (ret < 0)
 117                return ret;
 118        return 0;
 119}
 120
 121static int write_device(struct i2c_client *i2c, int reg,
 122                        int bytes, void *src)
 123{
 124        unsigned char buf[bytes + 1];
 125        struct i2c_adapter *adap = i2c->adapter;
 126        struct i2c_msg msg;
 127        int ret;
 128
 129        buf[0] = (unsigned char)reg;
 130        memcpy(&buf[1], src, bytes);
 131        msg.addr = i2c->addr;
 132        msg.flags = 0;
 133        msg.len = bytes + 1;
 134        msg.buf = buf;
 135
 136        ret = adap->algo->master_xfer(adap, &msg, 1);
 137        if (ret < 0)
 138                return ret;
 139        return 0;
 140}
 141
 142int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
 143{
 144        unsigned char zero = 0;
 145        unsigned char data;
 146        int ret;
 147
 148        i2c_lock_adapter(i2c->adapter);
 149        read_device(i2c, 0xFA, 0, &zero);
 150        read_device(i2c, 0xFB, 0, &zero);
 151        read_device(i2c, 0xFF, 0, &zero);
 152        ret = read_device(i2c, reg, 1, &data);
 153        if (ret >= 0)
 154                ret = (int)data;
 155        read_device(i2c, 0xFE, 0, &zero);
 156        read_device(i2c, 0xFC, 0, &zero);
 157        i2c_unlock_adapter(i2c->adapter);
 158        return ret;
 159}
 160EXPORT_SYMBOL(pm860x_page_reg_read);
 161
 162int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
 163                          unsigned char data)
 164{
 165        unsigned char zero;
 166        int ret;
 167
 168        i2c_lock_adapter(i2c->adapter);
 169        read_device(i2c, 0xFA, 0, &zero);
 170        read_device(i2c, 0xFB, 0, &zero);
 171        read_device(i2c, 0xFF, 0, &zero);
 172        ret = write_device(i2c, reg, 1, &data);
 173        read_device(i2c, 0xFE, 0, &zero);
 174        read_device(i2c, 0xFC, 0, &zero);
 175        i2c_unlock_adapter(i2c->adapter);
 176        return ret;
 177}
 178EXPORT_SYMBOL(pm860x_page_reg_write);
 179
 180int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
 181                          int count, unsigned char *buf)
 182{
 183        unsigned char zero = 0;
 184        int ret;
 185
 186        i2c_lock_adapter(i2c->adapter);
 187        read_device(i2c, 0xfa, 0, &zero);
 188        read_device(i2c, 0xfb, 0, &zero);
 189        read_device(i2c, 0xff, 0, &zero);
 190        ret = read_device(i2c, reg, count, buf);
 191        read_device(i2c, 0xFE, 0, &zero);
 192        read_device(i2c, 0xFC, 0, &zero);
 193        i2c_unlock_adapter(i2c->adapter);
 194        return ret;
 195}
 196EXPORT_SYMBOL(pm860x_page_bulk_read);
 197
 198int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
 199                           int count, unsigned char *buf)
 200{
 201        unsigned char zero = 0;
 202        int ret;
 203
 204        i2c_lock_adapter(i2c->adapter);
 205        read_device(i2c, 0xFA, 0, &zero);
 206        read_device(i2c, 0xFB, 0, &zero);
 207        read_device(i2c, 0xFF, 0, &zero);
 208        ret = write_device(i2c, reg, count, buf);
 209        read_device(i2c, 0xFE, 0, &zero);
 210        read_device(i2c, 0xFC, 0, &zero);
 211        i2c_unlock_adapter(i2c->adapter);
 212        i2c_unlock_adapter(i2c->adapter);
 213        return ret;
 214}
 215EXPORT_SYMBOL(pm860x_page_bulk_write);
 216
 217int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
 218                         unsigned char mask, unsigned char data)
 219{
 220        unsigned char zero;
 221        unsigned char value;
 222        int ret;
 223
 224        i2c_lock_adapter(i2c->adapter);
 225        read_device(i2c, 0xFA, 0, &zero);
 226        read_device(i2c, 0xFB, 0, &zero);
 227        read_device(i2c, 0xFF, 0, &zero);
 228        ret = read_device(i2c, reg, 1, &value);
 229        if (ret < 0)
 230                goto out;
 231        value &= ~mask;
 232        value |= data;
 233        ret = write_device(i2c, reg, 1, &value);
 234out:
 235        read_device(i2c, 0xFE, 0, &zero);
 236        read_device(i2c, 0xFC, 0, &zero);
 237        i2c_unlock_adapter(i2c->adapter);
 238        return ret;
 239}
 240EXPORT_SYMBOL(pm860x_page_set_bits);
 241