blob: cd53a823c0c51303a28239348144cf636970bdda [file] [log] [blame]
Haojian Zhuangbbd51b12010-01-06 17:04:18 -05001/*
Haojian Zhuang53dbab72010-01-08 06:01:24 -05002 * I2C driver for Marvell 88PM860x
Haojian Zhuangbbd51b12010-01-06 17:04:18 -05003 *
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>
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050013#include <linux/i2c.h>
Jett.Zhoub46a36c2011-11-11 15:38:27 +080014#include <linux/regmap.h>
Haojian Zhuang53dbab72010-01-08 06:01:24 -050015#include <linux/mfd/88pm860x.h>
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050016
Haojian Zhuang53dbab72010-01-08 06:01:24 -050017int pm860x_reg_read(struct i2c_client *i2c, int reg)
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050018{
Haojian Zhuang53dbab72010-01-08 06:01:24 -050019 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
Jett.Zhoub46a36c2011-11-11 15:38:27 +080020 struct regmap *map = (i2c == chip->client) ? chip->regmap
21 : chip->regmap_companion;
22 unsigned int data;
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050023 int ret;
24
Jett.Zhoub46a36c2011-11-11 15:38:27 +080025 ret = regmap_read(map, reg, &data);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050026 if (ret < 0)
27 return ret;
28 else
29 return (int)data;
30}
Haojian Zhuang53dbab72010-01-08 06:01:24 -050031EXPORT_SYMBOL(pm860x_reg_read);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050032
Haojian Zhuang53dbab72010-01-08 06:01:24 -050033int pm860x_reg_write(struct i2c_client *i2c, int reg,
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050034 unsigned char data)
35{
Haojian Zhuang53dbab72010-01-08 06:01:24 -050036 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
Jett.Zhoub46a36c2011-11-11 15:38:27 +080037 struct regmap *map = (i2c == chip->client) ? chip->regmap
38 : chip->regmap_companion;
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050039 int ret;
40
Jett.Zhoub46a36c2011-11-11 15:38:27 +080041 ret = regmap_write(map, reg, data);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050042 return ret;
43}
Haojian Zhuang53dbab72010-01-08 06:01:24 -050044EXPORT_SYMBOL(pm860x_reg_write);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050045
Haojian Zhuang53dbab72010-01-08 06:01:24 -050046int pm860x_bulk_read(struct i2c_client *i2c, int reg,
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050047 int count, unsigned char *buf)
48{
Haojian Zhuang53dbab72010-01-08 06:01:24 -050049 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
Jett.Zhoub46a36c2011-11-11 15:38:27 +080050 struct regmap *map = (i2c == chip->client) ? chip->regmap
51 : chip->regmap_companion;
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050052 int ret;
53
Jett.Zhoub46a36c2011-11-11 15:38:27 +080054 ret = regmap_raw_read(map, reg, buf, count);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050055 return ret;
56}
Haojian Zhuang53dbab72010-01-08 06:01:24 -050057EXPORT_SYMBOL(pm860x_bulk_read);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050058
Haojian Zhuang53dbab72010-01-08 06:01:24 -050059int pm860x_bulk_write(struct i2c_client *i2c, int reg,
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050060 int count, unsigned char *buf)
61{
Haojian Zhuang53dbab72010-01-08 06:01:24 -050062 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
Jett.Zhoub46a36c2011-11-11 15:38:27 +080063 struct regmap *map = (i2c == chip->client) ? chip->regmap
64 : chip->regmap_companion;
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050065 int ret;
66
Jett.Zhoub46a36c2011-11-11 15:38:27 +080067 ret = regmap_raw_write(map, reg, buf, count);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050068 return ret;
69}
Haojian Zhuang53dbab72010-01-08 06:01:24 -050070EXPORT_SYMBOL(pm860x_bulk_write);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050071
Haojian Zhuang53dbab72010-01-08 06:01:24 -050072int pm860x_set_bits(struct i2c_client *i2c, int reg,
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050073 unsigned char mask, unsigned char data)
74{
Haojian Zhuang53dbab72010-01-08 06:01:24 -050075 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
Jett.Zhoub46a36c2011-11-11 15:38:27 +080076 struct regmap *map = (i2c == chip->client) ? chip->regmap
77 : chip->regmap_companion;
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050078 int ret;
79
Jett.Zhoub46a36c2011-11-11 15:38:27 +080080 ret = regmap_update_bits(map, reg, mask, data);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050081 return ret;
82}
Haojian Zhuang53dbab72010-01-08 06:01:24 -050083EXPORT_SYMBOL(pm860x_set_bits);
Haojian Zhuangbbd51b12010-01-06 17:04:18 -050084
Jett.Zhou5bdf7412011-11-11 15:38:26 +080085static 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] = {{i2c->addr, 0, 1, msgbuf0},
92 {i2c->addr, I2C_M_RD, 0, msgbuf1},
93 };
94 int num = 1, ret = 0;
95
96 if (dest == NULL)
97 return -EINVAL;
98 msgbuf0[0] = (unsigned char)reg; /* command */
99 msg[1].len = bytes;
100
101 /* if data needs to read back, num should be 2 */
102 if (bytes > 0)
103 num = 2;
104 ret = adap->algo->master_xfer(adap, msg, num);
105 memcpy(dest, msgbuf1, bytes);
106 if (ret < 0)
107 return ret;
108 return 0;
109}
110
111static int write_device(struct i2c_client *i2c, int reg,
112 int bytes, void *src)
113{
114 unsigned char buf[bytes + 1];
115 struct i2c_adapter *adap = i2c->adapter;
116 struct i2c_msg msg;
117 int ret;
118
119 buf[0] = (unsigned char)reg;
120 memcpy(&buf[1], src, bytes);
121 msg.addr = i2c->addr;
122 msg.flags = 0;
123 msg.len = bytes + 1;
124 msg.buf = buf;
125
126 ret = adap->algo->master_xfer(adap, &msg, 1);
127 if (ret < 0)
128 return ret;
129 return 0;
130}
131
Haojian Zhuang09b03412011-03-07 23:43:16 +0800132int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
133{
Haojian Zhuang09b03412011-03-07 23:43:16 +0800134 unsigned char zero = 0;
135 unsigned char data;
136 int ret;
137
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800138 i2c_lock_adapter(i2c->adapter);
139 read_device(i2c, 0xFA, 0, &zero);
140 read_device(i2c, 0xFB, 0, &zero);
141 read_device(i2c, 0xFF, 0, &zero);
142 ret = read_device(i2c, reg, 1, &data);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800143 if (ret >= 0)
144 ret = (int)data;
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800145 read_device(i2c, 0xFE, 0, &zero);
146 read_device(i2c, 0xFC, 0, &zero);
147 i2c_unlock_adapter(i2c->adapter);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800148 return ret;
149}
150EXPORT_SYMBOL(pm860x_page_reg_read);
151
152int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
153 unsigned char data)
154{
Haojian Zhuang09b03412011-03-07 23:43:16 +0800155 unsigned char zero;
156 int ret;
157
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800158 i2c_lock_adapter(i2c->adapter);
159 read_device(i2c, 0xFA, 0, &zero);
160 read_device(i2c, 0xFB, 0, &zero);
161 read_device(i2c, 0xFF, 0, &zero);
162 ret = write_device(i2c, reg, 1, &data);
163 read_device(i2c, 0xFE, 0, &zero);
164 read_device(i2c, 0xFC, 0, &zero);
165 i2c_unlock_adapter(i2c->adapter);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800166 return ret;
167}
168EXPORT_SYMBOL(pm860x_page_reg_write);
169
170int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
171 int count, unsigned char *buf)
172{
Haojian Zhuang09b03412011-03-07 23:43:16 +0800173 unsigned char zero = 0;
174 int ret;
175
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800176 i2c_lock_adapter(i2c->adapter);
177 read_device(i2c, 0xfa, 0, &zero);
178 read_device(i2c, 0xfb, 0, &zero);
179 read_device(i2c, 0xff, 0, &zero);
180 ret = read_device(i2c, reg, count, buf);
181 read_device(i2c, 0xFE, 0, &zero);
182 read_device(i2c, 0xFC, 0, &zero);
183 i2c_unlock_adapter(i2c->adapter);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800184 return ret;
185}
186EXPORT_SYMBOL(pm860x_page_bulk_read);
187
188int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
189 int count, unsigned char *buf)
190{
Haojian Zhuang09b03412011-03-07 23:43:16 +0800191 unsigned char zero = 0;
192 int ret;
193
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800194 i2c_lock_adapter(i2c->adapter);
195 read_device(i2c, 0xFA, 0, &zero);
196 read_device(i2c, 0xFB, 0, &zero);
197 read_device(i2c, 0xFF, 0, &zero);
198 ret = write_device(i2c, reg, count, buf);
199 read_device(i2c, 0xFE, 0, &zero);
200 read_device(i2c, 0xFC, 0, &zero);
201 i2c_unlock_adapter(i2c->adapter);
202 i2c_unlock_adapter(i2c->adapter);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800203 return ret;
204}
205EXPORT_SYMBOL(pm860x_page_bulk_write);
206
207int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
208 unsigned char mask, unsigned char data)
209{
Haojian Zhuang09b03412011-03-07 23:43:16 +0800210 unsigned char zero;
211 unsigned char value;
212 int ret;
213
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800214 i2c_lock_adapter(i2c->adapter);
215 read_device(i2c, 0xFA, 0, &zero);
216 read_device(i2c, 0xFB, 0, &zero);
217 read_device(i2c, 0xFF, 0, &zero);
218 ret = read_device(i2c, reg, 1, &value);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800219 if (ret < 0)
220 goto out;
221 value &= ~mask;
222 value |= data;
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800223 ret = write_device(i2c, reg, 1, &value);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800224out:
Jett.Zhou5bdf7412011-11-11 15:38:26 +0800225 read_device(i2c, 0xFE, 0, &zero);
226 read_device(i2c, 0xFC, 0, &zero);
227 i2c_unlock_adapter(i2c->adapter);
Haojian Zhuang09b03412011-03-07 23:43:16 +0800228 return ret;
229}
230EXPORT_SYMBOL(pm860x_page_set_bits);