1bbd51b1fSHaojian Zhuang /* 253dbab7aSHaojian Zhuang * I2C driver for Marvell 88PM860x 3bbd51b1fSHaojian Zhuang * 4bbd51b1fSHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 50363be8bSLee Jones * 60363be8bSLee Jones * Author: Haojian Zhuang <haojian.zhuang@marvell.com> 7bbd51b1fSHaojian Zhuang * 8bbd51b1fSHaojian Zhuang * This program is free software; you can redistribute it and/or modify 9bbd51b1fSHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 10bbd51b1fSHaojian Zhuang * published by the Free Software Foundation. 11bbd51b1fSHaojian Zhuang */ 12bbd51b1fSHaojian Zhuang #include <linux/kernel.h> 13bbd51b1fSHaojian Zhuang #include <linux/module.h> 14bbd51b1fSHaojian Zhuang #include <linux/i2c.h> 15b46a36c0SJett.Zhou #include <linux/regmap.h> 1653dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h> 17bbd51b1fSHaojian Zhuang 1853dbab7aSHaojian Zhuang int pm860x_reg_read(struct i2c_client *i2c, int reg) 19bbd51b1fSHaojian Zhuang { 2053dbab7aSHaojian Zhuang struct pm860x_chip *chip = i2c_get_clientdata(i2c); 21b46a36c0SJett.Zhou struct regmap *map = (i2c == chip->client) ? chip->regmap 22b46a36c0SJett.Zhou : chip->regmap_companion; 23b46a36c0SJett.Zhou unsigned int data; 24bbd51b1fSHaojian Zhuang int ret; 25bbd51b1fSHaojian Zhuang 26b46a36c0SJett.Zhou ret = regmap_read(map, reg, &data); 27bbd51b1fSHaojian Zhuang if (ret < 0) 28bbd51b1fSHaojian Zhuang return ret; 29bbd51b1fSHaojian Zhuang else 30bbd51b1fSHaojian Zhuang return (int)data; 31bbd51b1fSHaojian Zhuang } 3253dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_reg_read); 33bbd51b1fSHaojian Zhuang 3453dbab7aSHaojian Zhuang int pm860x_reg_write(struct i2c_client *i2c, int reg, 35bbd51b1fSHaojian Zhuang unsigned char data) 36bbd51b1fSHaojian Zhuang { 3753dbab7aSHaojian Zhuang struct pm860x_chip *chip = i2c_get_clientdata(i2c); 38b46a36c0SJett.Zhou struct regmap *map = (i2c == chip->client) ? chip->regmap 39b46a36c0SJett.Zhou : chip->regmap_companion; 40bbd51b1fSHaojian Zhuang int ret; 41bbd51b1fSHaojian Zhuang 42b46a36c0SJett.Zhou ret = regmap_write(map, reg, data); 43bbd51b1fSHaojian Zhuang return ret; 44bbd51b1fSHaojian Zhuang } 4553dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_reg_write); 46bbd51b1fSHaojian Zhuang 4753dbab7aSHaojian Zhuang int pm860x_bulk_read(struct i2c_client *i2c, int reg, 48bbd51b1fSHaojian Zhuang int count, unsigned char *buf) 49bbd51b1fSHaojian Zhuang { 5053dbab7aSHaojian Zhuang struct pm860x_chip *chip = i2c_get_clientdata(i2c); 51b46a36c0SJett.Zhou struct regmap *map = (i2c == chip->client) ? chip->regmap 52b46a36c0SJett.Zhou : chip->regmap_companion; 53bbd51b1fSHaojian Zhuang int ret; 54bbd51b1fSHaojian Zhuang 55b46a36c0SJett.Zhou ret = regmap_raw_read(map, reg, buf, count); 56bbd51b1fSHaojian Zhuang return ret; 57bbd51b1fSHaojian Zhuang } 5853dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_bulk_read); 59bbd51b1fSHaojian Zhuang 6053dbab7aSHaojian Zhuang int pm860x_bulk_write(struct i2c_client *i2c, int reg, 61bbd51b1fSHaojian Zhuang int count, unsigned char *buf) 62bbd51b1fSHaojian Zhuang { 6353dbab7aSHaojian Zhuang struct pm860x_chip *chip = i2c_get_clientdata(i2c); 64b46a36c0SJett.Zhou struct regmap *map = (i2c == chip->client) ? chip->regmap 65b46a36c0SJett.Zhou : chip->regmap_companion; 66bbd51b1fSHaojian Zhuang int ret; 67bbd51b1fSHaojian Zhuang 68b46a36c0SJett.Zhou ret = regmap_raw_write(map, reg, buf, count); 69bbd51b1fSHaojian Zhuang return ret; 70bbd51b1fSHaojian Zhuang } 7153dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_bulk_write); 72bbd51b1fSHaojian Zhuang 7353dbab7aSHaojian Zhuang int pm860x_set_bits(struct i2c_client *i2c, int reg, 74bbd51b1fSHaojian Zhuang unsigned char mask, unsigned char data) 75bbd51b1fSHaojian Zhuang { 7653dbab7aSHaojian Zhuang struct pm860x_chip *chip = i2c_get_clientdata(i2c); 77b46a36c0SJett.Zhou struct regmap *map = (i2c == chip->client) ? chip->regmap 78b46a36c0SJett.Zhou : chip->regmap_companion; 79bbd51b1fSHaojian Zhuang int ret; 80bbd51b1fSHaojian Zhuang 81b46a36c0SJett.Zhou ret = regmap_update_bits(map, reg, mask, data); 82bbd51b1fSHaojian Zhuang return ret; 83bbd51b1fSHaojian Zhuang } 8453dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_set_bits); 85bbd51b1fSHaojian Zhuang 865bdf7411SJett.Zhou static int read_device(struct i2c_client *i2c, int reg, 875bdf7411SJett.Zhou int bytes, void *dest) 885bdf7411SJett.Zhou { 895bdf7411SJett.Zhou unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; 905bdf7411SJett.Zhou unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; 915bdf7411SJett.Zhou struct i2c_adapter *adap = i2c->adapter; 9248942222SShubhrajyoti D struct i2c_msg msg[2] = { 9348942222SShubhrajyoti D { 9448942222SShubhrajyoti D .addr = i2c->addr, 9548942222SShubhrajyoti D .flags = 0, 9648942222SShubhrajyoti D .len = 1, 9748942222SShubhrajyoti D .buf = msgbuf0 9848942222SShubhrajyoti D }, 9948942222SShubhrajyoti D { .addr = i2c->addr, 10048942222SShubhrajyoti D .flags = I2C_M_RD, 10148942222SShubhrajyoti D .len = 0, 10248942222SShubhrajyoti D .buf = msgbuf1 10348942222SShubhrajyoti D }, 1045bdf7411SJett.Zhou }; 1055bdf7411SJett.Zhou int num = 1, ret = 0; 1065bdf7411SJett.Zhou 1075bdf7411SJett.Zhou if (dest == NULL) 1085bdf7411SJett.Zhou return -EINVAL; 1095bdf7411SJett.Zhou msgbuf0[0] = (unsigned char)reg; /* command */ 1105bdf7411SJett.Zhou msg[1].len = bytes; 1115bdf7411SJett.Zhou 1125bdf7411SJett.Zhou /* if data needs to read back, num should be 2 */ 1135bdf7411SJett.Zhou if (bytes > 0) 1145bdf7411SJett.Zhou num = 2; 1155bdf7411SJett.Zhou ret = adap->algo->master_xfer(adap, msg, num); 1165bdf7411SJett.Zhou memcpy(dest, msgbuf1, bytes); 1175bdf7411SJett.Zhou if (ret < 0) 1185bdf7411SJett.Zhou return ret; 1195bdf7411SJett.Zhou return 0; 1205bdf7411SJett.Zhou } 1215bdf7411SJett.Zhou 1225bdf7411SJett.Zhou static int write_device(struct i2c_client *i2c, int reg, 1235bdf7411SJett.Zhou int bytes, void *src) 1245bdf7411SJett.Zhou { 1255bdf7411SJett.Zhou unsigned char buf[bytes + 1]; 1265bdf7411SJett.Zhou struct i2c_adapter *adap = i2c->adapter; 1275bdf7411SJett.Zhou struct i2c_msg msg; 1285bdf7411SJett.Zhou int ret; 1295bdf7411SJett.Zhou 1305bdf7411SJett.Zhou buf[0] = (unsigned char)reg; 1315bdf7411SJett.Zhou memcpy(&buf[1], src, bytes); 1325bdf7411SJett.Zhou msg.addr = i2c->addr; 1335bdf7411SJett.Zhou msg.flags = 0; 1345bdf7411SJett.Zhou msg.len = bytes + 1; 1355bdf7411SJett.Zhou msg.buf = buf; 1365bdf7411SJett.Zhou 1375bdf7411SJett.Zhou ret = adap->algo->master_xfer(adap, &msg, 1); 1385bdf7411SJett.Zhou if (ret < 0) 1395bdf7411SJett.Zhou return ret; 1405bdf7411SJett.Zhou return 0; 1415bdf7411SJett.Zhou } 1425bdf7411SJett.Zhou 14309b03419SHaojian Zhuang int pm860x_page_reg_read(struct i2c_client *i2c, int reg) 14409b03419SHaojian Zhuang { 14509b03419SHaojian Zhuang unsigned char zero = 0; 14609b03419SHaojian Zhuang unsigned char data; 14709b03419SHaojian Zhuang int ret; 14809b03419SHaojian Zhuang 1495bdf7411SJett.Zhou i2c_lock_adapter(i2c->adapter); 1505bdf7411SJett.Zhou read_device(i2c, 0xFA, 0, &zero); 1515bdf7411SJett.Zhou read_device(i2c, 0xFB, 0, &zero); 1525bdf7411SJett.Zhou read_device(i2c, 0xFF, 0, &zero); 1535bdf7411SJett.Zhou ret = read_device(i2c, reg, 1, &data); 15409b03419SHaojian Zhuang if (ret >= 0) 15509b03419SHaojian Zhuang ret = (int)data; 1565bdf7411SJett.Zhou read_device(i2c, 0xFE, 0, &zero); 1575bdf7411SJett.Zhou read_device(i2c, 0xFC, 0, &zero); 1585bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 15909b03419SHaojian Zhuang return ret; 16009b03419SHaojian Zhuang } 16109b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_reg_read); 16209b03419SHaojian Zhuang 16309b03419SHaojian Zhuang int pm860x_page_reg_write(struct i2c_client *i2c, int reg, 16409b03419SHaojian Zhuang unsigned char data) 16509b03419SHaojian Zhuang { 16609b03419SHaojian Zhuang unsigned char zero; 16709b03419SHaojian Zhuang int ret; 16809b03419SHaojian Zhuang 1695bdf7411SJett.Zhou i2c_lock_adapter(i2c->adapter); 1705bdf7411SJett.Zhou read_device(i2c, 0xFA, 0, &zero); 1715bdf7411SJett.Zhou read_device(i2c, 0xFB, 0, &zero); 1725bdf7411SJett.Zhou read_device(i2c, 0xFF, 0, &zero); 1735bdf7411SJett.Zhou ret = write_device(i2c, reg, 1, &data); 1745bdf7411SJett.Zhou read_device(i2c, 0xFE, 0, &zero); 1755bdf7411SJett.Zhou read_device(i2c, 0xFC, 0, &zero); 1765bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 17709b03419SHaojian Zhuang return ret; 17809b03419SHaojian Zhuang } 17909b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_reg_write); 18009b03419SHaojian Zhuang 18109b03419SHaojian Zhuang int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, 18209b03419SHaojian Zhuang int count, unsigned char *buf) 18309b03419SHaojian Zhuang { 18409b03419SHaojian Zhuang unsigned char zero = 0; 18509b03419SHaojian Zhuang int ret; 18609b03419SHaojian Zhuang 1875bdf7411SJett.Zhou i2c_lock_adapter(i2c->adapter); 1885bdf7411SJett.Zhou read_device(i2c, 0xfa, 0, &zero); 1895bdf7411SJett.Zhou read_device(i2c, 0xfb, 0, &zero); 1905bdf7411SJett.Zhou read_device(i2c, 0xff, 0, &zero); 1915bdf7411SJett.Zhou ret = read_device(i2c, reg, count, buf); 1925bdf7411SJett.Zhou read_device(i2c, 0xFE, 0, &zero); 1935bdf7411SJett.Zhou read_device(i2c, 0xFC, 0, &zero); 1945bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 19509b03419SHaojian Zhuang return ret; 19609b03419SHaojian Zhuang } 19709b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_bulk_read); 19809b03419SHaojian Zhuang 19909b03419SHaojian Zhuang int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, 20009b03419SHaojian Zhuang int count, unsigned char *buf) 20109b03419SHaojian Zhuang { 20209b03419SHaojian Zhuang unsigned char zero = 0; 20309b03419SHaojian Zhuang int ret; 20409b03419SHaojian Zhuang 2055bdf7411SJett.Zhou i2c_lock_adapter(i2c->adapter); 2065bdf7411SJett.Zhou read_device(i2c, 0xFA, 0, &zero); 2075bdf7411SJett.Zhou read_device(i2c, 0xFB, 0, &zero); 2085bdf7411SJett.Zhou read_device(i2c, 0xFF, 0, &zero); 2095bdf7411SJett.Zhou ret = write_device(i2c, reg, count, buf); 2105bdf7411SJett.Zhou read_device(i2c, 0xFE, 0, &zero); 2115bdf7411SJett.Zhou read_device(i2c, 0xFC, 0, &zero); 2125bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 2135bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 21409b03419SHaojian Zhuang return ret; 21509b03419SHaojian Zhuang } 21609b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_bulk_write); 21709b03419SHaojian Zhuang 21809b03419SHaojian Zhuang int pm860x_page_set_bits(struct i2c_client *i2c, int reg, 21909b03419SHaojian Zhuang unsigned char mask, unsigned char data) 22009b03419SHaojian Zhuang { 22109b03419SHaojian Zhuang unsigned char zero; 22209b03419SHaojian Zhuang unsigned char value; 22309b03419SHaojian Zhuang int ret; 22409b03419SHaojian Zhuang 2255bdf7411SJett.Zhou i2c_lock_adapter(i2c->adapter); 2265bdf7411SJett.Zhou read_device(i2c, 0xFA, 0, &zero); 2275bdf7411SJett.Zhou read_device(i2c, 0xFB, 0, &zero); 2285bdf7411SJett.Zhou read_device(i2c, 0xFF, 0, &zero); 2295bdf7411SJett.Zhou ret = read_device(i2c, reg, 1, &value); 23009b03419SHaojian Zhuang if (ret < 0) 23109b03419SHaojian Zhuang goto out; 23209b03419SHaojian Zhuang value &= ~mask; 23309b03419SHaojian Zhuang value |= data; 2345bdf7411SJett.Zhou ret = write_device(i2c, reg, 1, &value); 23509b03419SHaojian Zhuang out: 2365bdf7411SJett.Zhou read_device(i2c, 0xFE, 0, &zero); 2375bdf7411SJett.Zhou read_device(i2c, 0xFC, 0, &zero); 2385bdf7411SJett.Zhou i2c_unlock_adapter(i2c->adapter); 23909b03419SHaojian Zhuang return ret; 24009b03419SHaojian Zhuang } 24109b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_set_bits); 242