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 17 int 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 } 31 EXPORT_SYMBOL(pm860x_reg_read); 32 33 int 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 } 44 EXPORT_SYMBOL(pm860x_reg_write); 45 46 int 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 } 57 EXPORT_SYMBOL(pm860x_bulk_read); 58 59 int 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 } 70 EXPORT_SYMBOL(pm860x_bulk_write); 71 72 int 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 } 83 EXPORT_SYMBOL(pm860x_set_bits); 84 85 static 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 121 static 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 142 int 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 } 160 EXPORT_SYMBOL(pm860x_page_reg_read); 161 162 int 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 } 178 EXPORT_SYMBOL(pm860x_page_reg_write); 179 180 int 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 } 196 EXPORT_SYMBOL(pm860x_page_bulk_read); 197 198 int 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 } 215 EXPORT_SYMBOL(pm860x_page_bulk_write); 216 217 int 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); 234 out: 235 read_device(i2c, 0xFE, 0, &zero); 236 read_device(i2c, 0xFC, 0, &zero); 237 i2c_unlock_adapter(i2c->adapter); 238 return ret; 239 } 240 EXPORT_SYMBOL(pm860x_page_set_bits); 241