xref: /openbmc/linux/drivers/mfd/88pm860x-i2c.c (revision 0363be8b)
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