88pm860x-i2c.c revision b46a36c0e0adc92c8be2c8a6fa68d979f6eee124
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 return ret; 290 } 291 chip->client = client; 292 i2c_set_clientdata(client, chip); 293 chip->dev = &client->dev; 294 dev_set_drvdata(chip->dev, chip); 295 296 /* 297 * Both client and companion client shares same platform driver. 298 * Driver distinguishes them by pdata->companion_addr. 299 * pdata->companion_addr is only assigned if companion chip exists. 300 * At the same time, the companion_addr shouldn't equal to client 301 * address. 302 */ 303 if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { 304 chip->companion_addr = pdata->companion_addr; 305 chip->companion = i2c_new_dummy(chip->client->adapter, 306 chip->companion_addr); 307 chip->regmap_companion = regmap_init_i2c(chip->companion, 308 &pm860x_regmap_config); 309 if (IS_ERR(chip->regmap_companion)) { 310 ret = PTR_ERR(chip->regmap_companion); 311 dev_err(&chip->companion->dev, 312 "Failed to allocate register map: %d\n", ret); 313 return ret; 314 } 315 i2c_set_clientdata(chip->companion, chip); 316 } 317 318 pm860x_device_init(chip, pdata); 319 return 0; 320} 321 322static int __devexit pm860x_remove(struct i2c_client *client) 323{ 324 struct pm860x_chip *chip = i2c_get_clientdata(client); 325 326 pm860x_device_exit(chip); 327 if (chip->companion) { 328 regmap_exit(chip->regmap_companion); 329 i2c_unregister_device(chip->companion); 330 } 331 regmap_exit(chip->regmap); 332 kfree(chip); 333 return 0; 334} 335 336static struct i2c_driver pm860x_driver = { 337 .driver = { 338 .name = "88PM860x", 339 .owner = THIS_MODULE, 340 }, 341 .probe = pm860x_probe, 342 .remove = __devexit_p(pm860x_remove), 343 .id_table = pm860x_id_table, 344}; 345 346static int __init pm860x_i2c_init(void) 347{ 348 int ret; 349 ret = i2c_add_driver(&pm860x_driver); 350 if (ret != 0) 351 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); 352 return ret; 353} 354subsys_initcall(pm860x_i2c_init); 355 356static void __exit pm860x_i2c_exit(void) 357{ 358 i2c_del_driver(&pm860x_driver); 359} 360module_exit(pm860x_i2c_exit); 361 362MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x"); 363MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 364MODULE_LICENSE("GPL"); 365