xref: /openbmc/linux/drivers/mfd/88pm860x-i2c.c (revision 48942222)
1bbd51b1fSHaojian Zhuang /*
253dbab7aSHaojian Zhuang  * I2C driver for Marvell 88PM860x
3bbd51b1fSHaojian Zhuang  *
4bbd51b1fSHaojian Zhuang  * Copyright (C) 2009 Marvell International Ltd.
5bbd51b1fSHaojian Zhuang  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6bbd51b1fSHaojian Zhuang  *
7bbd51b1fSHaojian Zhuang  * This program is free software; you can redistribute it and/or modify
8bbd51b1fSHaojian Zhuang  * it under the terms of the GNU General Public License version 2 as
9bbd51b1fSHaojian Zhuang  * published by the Free Software Foundation.
10bbd51b1fSHaojian Zhuang  */
11bbd51b1fSHaojian Zhuang #include <linux/kernel.h>
12bbd51b1fSHaojian Zhuang #include <linux/module.h>
13bbd51b1fSHaojian Zhuang #include <linux/i2c.h>
14b46a36c0SJett.Zhou #include <linux/regmap.h>
1553dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h>
16bbd51b1fSHaojian Zhuang 
1753dbab7aSHaojian Zhuang int pm860x_reg_read(struct i2c_client *i2c, int reg)
18bbd51b1fSHaojian Zhuang {
1953dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
20b46a36c0SJett.Zhou 	struct regmap *map = (i2c == chip->client) ? chip->regmap
21b46a36c0SJett.Zhou 				: chip->regmap_companion;
22b46a36c0SJett.Zhou 	unsigned int data;
23bbd51b1fSHaojian Zhuang 	int ret;
24bbd51b1fSHaojian Zhuang 
25b46a36c0SJett.Zhou 	ret = regmap_read(map, reg, &data);
26bbd51b1fSHaojian Zhuang 	if (ret < 0)
27bbd51b1fSHaojian Zhuang 		return ret;
28bbd51b1fSHaojian Zhuang 	else
29bbd51b1fSHaojian Zhuang 		return (int)data;
30bbd51b1fSHaojian Zhuang }
3153dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_reg_read);
32bbd51b1fSHaojian Zhuang 
3353dbab7aSHaojian Zhuang int pm860x_reg_write(struct i2c_client *i2c, int reg,
34bbd51b1fSHaojian Zhuang 		     unsigned char data)
35bbd51b1fSHaojian Zhuang {
3653dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
37b46a36c0SJett.Zhou 	struct regmap *map = (i2c == chip->client) ? chip->regmap
38b46a36c0SJett.Zhou 				: chip->regmap_companion;
39bbd51b1fSHaojian Zhuang 	int ret;
40bbd51b1fSHaojian Zhuang 
41b46a36c0SJett.Zhou 	ret = regmap_write(map, reg, data);
42bbd51b1fSHaojian Zhuang 	return ret;
43bbd51b1fSHaojian Zhuang }
4453dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_reg_write);
45bbd51b1fSHaojian Zhuang 
4653dbab7aSHaojian Zhuang int pm860x_bulk_read(struct i2c_client *i2c, int reg,
47bbd51b1fSHaojian Zhuang 		     int count, unsigned char *buf)
48bbd51b1fSHaojian Zhuang {
4953dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
50b46a36c0SJett.Zhou 	struct regmap *map = (i2c == chip->client) ? chip->regmap
51b46a36c0SJett.Zhou 				: chip->regmap_companion;
52bbd51b1fSHaojian Zhuang 	int ret;
53bbd51b1fSHaojian Zhuang 
54b46a36c0SJett.Zhou 	ret = regmap_raw_read(map, reg, buf, count);
55bbd51b1fSHaojian Zhuang 	return ret;
56bbd51b1fSHaojian Zhuang }
5753dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_bulk_read);
58bbd51b1fSHaojian Zhuang 
5953dbab7aSHaojian Zhuang int pm860x_bulk_write(struct i2c_client *i2c, int reg,
60bbd51b1fSHaojian Zhuang 		      int count, unsigned char *buf)
61bbd51b1fSHaojian Zhuang {
6253dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
63b46a36c0SJett.Zhou 	struct regmap *map = (i2c == chip->client) ? chip->regmap
64b46a36c0SJett.Zhou 				: chip->regmap_companion;
65bbd51b1fSHaojian Zhuang 	int ret;
66bbd51b1fSHaojian Zhuang 
67b46a36c0SJett.Zhou 	ret = regmap_raw_write(map, reg, buf, count);
68bbd51b1fSHaojian Zhuang 	return ret;
69bbd51b1fSHaojian Zhuang }
7053dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_bulk_write);
71bbd51b1fSHaojian Zhuang 
7253dbab7aSHaojian Zhuang int pm860x_set_bits(struct i2c_client *i2c, int reg,
73bbd51b1fSHaojian Zhuang 		    unsigned char mask, unsigned char data)
74bbd51b1fSHaojian Zhuang {
7553dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
76b46a36c0SJett.Zhou 	struct regmap *map = (i2c == chip->client) ? chip->regmap
77b46a36c0SJett.Zhou 				: chip->regmap_companion;
78bbd51b1fSHaojian Zhuang 	int ret;
79bbd51b1fSHaojian Zhuang 
80b46a36c0SJett.Zhou 	ret = regmap_update_bits(map, reg, mask, data);
81bbd51b1fSHaojian Zhuang 	return ret;
82bbd51b1fSHaojian Zhuang }
8353dbab7aSHaojian Zhuang EXPORT_SYMBOL(pm860x_set_bits);
84bbd51b1fSHaojian Zhuang 
855bdf7411SJett.Zhou static int read_device(struct i2c_client *i2c, int reg,
865bdf7411SJett.Zhou 		       int bytes, void *dest)
875bdf7411SJett.Zhou {
885bdf7411SJett.Zhou 	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
895bdf7411SJett.Zhou 	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
905bdf7411SJett.Zhou 	struct i2c_adapter *adap = i2c->adapter;
9148942222SShubhrajyoti D 	struct i2c_msg msg[2] = {
9248942222SShubhrajyoti D 					{
9348942222SShubhrajyoti D 						.addr = i2c->addr,
9448942222SShubhrajyoti D 						.flags = 0,
9548942222SShubhrajyoti D 						.len = 1,
9648942222SShubhrajyoti D 						.buf = msgbuf0
9748942222SShubhrajyoti D 					},
9848942222SShubhrajyoti D 					{	.addr = i2c->addr,
9948942222SShubhrajyoti D 						.flags = I2C_M_RD,
10048942222SShubhrajyoti D 						.len = 0,
10148942222SShubhrajyoti D 						.buf = msgbuf1
10248942222SShubhrajyoti D 					},
1035bdf7411SJett.Zhou 				};
1045bdf7411SJett.Zhou 	int num = 1, ret = 0;
1055bdf7411SJett.Zhou 
1065bdf7411SJett.Zhou 	if (dest == NULL)
1075bdf7411SJett.Zhou 		return -EINVAL;
1085bdf7411SJett.Zhou 	msgbuf0[0] = (unsigned char)reg;	/* command */
1095bdf7411SJett.Zhou 	msg[1].len = bytes;
1105bdf7411SJett.Zhou 
1115bdf7411SJett.Zhou 	/* if data needs to read back, num should be 2 */
1125bdf7411SJett.Zhou 	if (bytes > 0)
1135bdf7411SJett.Zhou 		num = 2;
1145bdf7411SJett.Zhou 	ret = adap->algo->master_xfer(adap, msg, num);
1155bdf7411SJett.Zhou 	memcpy(dest, msgbuf1, bytes);
1165bdf7411SJett.Zhou 	if (ret < 0)
1175bdf7411SJett.Zhou 		return ret;
1185bdf7411SJett.Zhou 	return 0;
1195bdf7411SJett.Zhou }
1205bdf7411SJett.Zhou 
1215bdf7411SJett.Zhou static int write_device(struct i2c_client *i2c, int reg,
1225bdf7411SJett.Zhou 			int bytes, void *src)
1235bdf7411SJett.Zhou {
1245bdf7411SJett.Zhou 	unsigned char buf[bytes + 1];
1255bdf7411SJett.Zhou 	struct i2c_adapter *adap = i2c->adapter;
1265bdf7411SJett.Zhou 	struct i2c_msg msg;
1275bdf7411SJett.Zhou 	int ret;
1285bdf7411SJett.Zhou 
1295bdf7411SJett.Zhou 	buf[0] = (unsigned char)reg;
1305bdf7411SJett.Zhou 	memcpy(&buf[1], src, bytes);
1315bdf7411SJett.Zhou 	msg.addr = i2c->addr;
1325bdf7411SJett.Zhou 	msg.flags = 0;
1335bdf7411SJett.Zhou 	msg.len = bytes + 1;
1345bdf7411SJett.Zhou 	msg.buf = buf;
1355bdf7411SJett.Zhou 
1365bdf7411SJett.Zhou 	ret = adap->algo->master_xfer(adap, &msg, 1);
1375bdf7411SJett.Zhou 	if (ret < 0)
1385bdf7411SJett.Zhou 		return ret;
1395bdf7411SJett.Zhou 	return 0;
1405bdf7411SJett.Zhou }
1415bdf7411SJett.Zhou 
14209b03419SHaojian Zhuang int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
14309b03419SHaojian Zhuang {
14409b03419SHaojian Zhuang 	unsigned char zero = 0;
14509b03419SHaojian Zhuang 	unsigned char data;
14609b03419SHaojian Zhuang 	int ret;
14709b03419SHaojian Zhuang 
1485bdf7411SJett.Zhou 	i2c_lock_adapter(i2c->adapter);
1495bdf7411SJett.Zhou 	read_device(i2c, 0xFA, 0, &zero);
1505bdf7411SJett.Zhou 	read_device(i2c, 0xFB, 0, &zero);
1515bdf7411SJett.Zhou 	read_device(i2c, 0xFF, 0, &zero);
1525bdf7411SJett.Zhou 	ret = read_device(i2c, reg, 1, &data);
15309b03419SHaojian Zhuang 	if (ret >= 0)
15409b03419SHaojian Zhuang 		ret = (int)data;
1555bdf7411SJett.Zhou 	read_device(i2c, 0xFE, 0, &zero);
1565bdf7411SJett.Zhou 	read_device(i2c, 0xFC, 0, &zero);
1575bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
15809b03419SHaojian Zhuang 	return ret;
15909b03419SHaojian Zhuang }
16009b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_reg_read);
16109b03419SHaojian Zhuang 
16209b03419SHaojian Zhuang int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
16309b03419SHaojian Zhuang 			  unsigned char data)
16409b03419SHaojian Zhuang {
16509b03419SHaojian Zhuang 	unsigned char zero;
16609b03419SHaojian Zhuang 	int ret;
16709b03419SHaojian Zhuang 
1685bdf7411SJett.Zhou 	i2c_lock_adapter(i2c->adapter);
1695bdf7411SJett.Zhou 	read_device(i2c, 0xFA, 0, &zero);
1705bdf7411SJett.Zhou 	read_device(i2c, 0xFB, 0, &zero);
1715bdf7411SJett.Zhou 	read_device(i2c, 0xFF, 0, &zero);
1725bdf7411SJett.Zhou 	ret = write_device(i2c, reg, 1, &data);
1735bdf7411SJett.Zhou 	read_device(i2c, 0xFE, 0, &zero);
1745bdf7411SJett.Zhou 	read_device(i2c, 0xFC, 0, &zero);
1755bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
17609b03419SHaojian Zhuang 	return ret;
17709b03419SHaojian Zhuang }
17809b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_reg_write);
17909b03419SHaojian Zhuang 
18009b03419SHaojian Zhuang int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
18109b03419SHaojian Zhuang 			  int count, unsigned char *buf)
18209b03419SHaojian Zhuang {
18309b03419SHaojian Zhuang 	unsigned char zero = 0;
18409b03419SHaojian Zhuang 	int ret;
18509b03419SHaojian Zhuang 
1865bdf7411SJett.Zhou 	i2c_lock_adapter(i2c->adapter);
1875bdf7411SJett.Zhou 	read_device(i2c, 0xfa, 0, &zero);
1885bdf7411SJett.Zhou 	read_device(i2c, 0xfb, 0, &zero);
1895bdf7411SJett.Zhou 	read_device(i2c, 0xff, 0, &zero);
1905bdf7411SJett.Zhou 	ret = read_device(i2c, reg, count, buf);
1915bdf7411SJett.Zhou 	read_device(i2c, 0xFE, 0, &zero);
1925bdf7411SJett.Zhou 	read_device(i2c, 0xFC, 0, &zero);
1935bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
19409b03419SHaojian Zhuang 	return ret;
19509b03419SHaojian Zhuang }
19609b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_bulk_read);
19709b03419SHaojian Zhuang 
19809b03419SHaojian Zhuang int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
19909b03419SHaojian Zhuang 			   int count, unsigned char *buf)
20009b03419SHaojian Zhuang {
20109b03419SHaojian Zhuang 	unsigned char zero = 0;
20209b03419SHaojian Zhuang 	int ret;
20309b03419SHaojian Zhuang 
2045bdf7411SJett.Zhou 	i2c_lock_adapter(i2c->adapter);
2055bdf7411SJett.Zhou 	read_device(i2c, 0xFA, 0, &zero);
2065bdf7411SJett.Zhou 	read_device(i2c, 0xFB, 0, &zero);
2075bdf7411SJett.Zhou 	read_device(i2c, 0xFF, 0, &zero);
2085bdf7411SJett.Zhou 	ret = write_device(i2c, reg, count, buf);
2095bdf7411SJett.Zhou 	read_device(i2c, 0xFE, 0, &zero);
2105bdf7411SJett.Zhou 	read_device(i2c, 0xFC, 0, &zero);
2115bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
2125bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
21309b03419SHaojian Zhuang 	return ret;
21409b03419SHaojian Zhuang }
21509b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_bulk_write);
21609b03419SHaojian Zhuang 
21709b03419SHaojian Zhuang int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
21809b03419SHaojian Zhuang 			 unsigned char mask, unsigned char data)
21909b03419SHaojian Zhuang {
22009b03419SHaojian Zhuang 	unsigned char zero;
22109b03419SHaojian Zhuang 	unsigned char value;
22209b03419SHaojian Zhuang 	int ret;
22309b03419SHaojian Zhuang 
2245bdf7411SJett.Zhou 	i2c_lock_adapter(i2c->adapter);
2255bdf7411SJett.Zhou 	read_device(i2c, 0xFA, 0, &zero);
2265bdf7411SJett.Zhou 	read_device(i2c, 0xFB, 0, &zero);
2275bdf7411SJett.Zhou 	read_device(i2c, 0xFF, 0, &zero);
2285bdf7411SJett.Zhou 	ret = read_device(i2c, reg, 1, &value);
22909b03419SHaojian Zhuang 	if (ret < 0)
23009b03419SHaojian Zhuang 		goto out;
23109b03419SHaojian Zhuang 	value &= ~mask;
23209b03419SHaojian Zhuang 	value |= data;
2335bdf7411SJett.Zhou 	ret = write_device(i2c, reg, 1, &value);
23409b03419SHaojian Zhuang out:
2355bdf7411SJett.Zhou 	read_device(i2c, 0xFE, 0, &zero);
2365bdf7411SJett.Zhou 	read_device(i2c, 0xFC, 0, &zero);
2375bdf7411SJett.Zhou 	i2c_unlock_adapter(i2c->adapter);
23809b03419SHaojian Zhuang 	return ret;
23909b03419SHaojian Zhuang }
24009b03419SHaojian Zhuang EXPORT_SYMBOL(pm860x_page_set_bits);
241