2 * I2C driver for Marvell 88PM860x
4 * Copyright (C) 2009 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
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.
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/i2c.h>
15 #include <linux/mfd/88pm860x.h>
17 static inline int pm860x_read_device(struct i2c_client
*i2c
,
18 int reg
, int bytes
, void *dest
)
23 data
= (unsigned char)reg
;
24 ret
= i2c_master_send(i2c
, &data
, 1);
28 ret
= i2c_master_recv(i2c
, dest
, bytes
);
34 static inline int pm860x_write_device(struct i2c_client
*i2c
,
35 int reg
, int bytes
, void *src
)
37 unsigned char buf
[bytes
+ 1];
40 buf
[0] = (unsigned char)reg
;
41 memcpy(&buf
[1], src
, bytes
);
43 ret
= i2c_master_send(i2c
, buf
, bytes
+ 1);
49 int pm860x_reg_read(struct i2c_client
*i2c
, int reg
)
51 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
55 mutex_lock(&chip
->io_lock
);
56 ret
= pm860x_read_device(i2c
, reg
, 1, &data
);
57 mutex_unlock(&chip
->io_lock
);
64 EXPORT_SYMBOL(pm860x_reg_read
);
66 int pm860x_reg_write(struct i2c_client
*i2c
, int reg
,
69 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
72 mutex_lock(&chip
->io_lock
);
73 ret
= pm860x_write_device(i2c
, reg
, 1, &data
);
74 mutex_unlock(&chip
->io_lock
);
78 EXPORT_SYMBOL(pm860x_reg_write
);
80 int pm860x_bulk_read(struct i2c_client
*i2c
, int reg
,
81 int count
, unsigned char *buf
)
83 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
86 mutex_lock(&chip
->io_lock
);
87 ret
= pm860x_read_device(i2c
, reg
, count
, buf
);
88 mutex_unlock(&chip
->io_lock
);
92 EXPORT_SYMBOL(pm860x_bulk_read
);
94 int pm860x_bulk_write(struct i2c_client
*i2c
, int reg
,
95 int count
, unsigned char *buf
)
97 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
100 mutex_lock(&chip
->io_lock
);
101 ret
= pm860x_write_device(i2c
, reg
, count
, buf
);
102 mutex_unlock(&chip
->io_lock
);
106 EXPORT_SYMBOL(pm860x_bulk_write
);
108 int pm860x_set_bits(struct i2c_client
*i2c
, int reg
,
109 unsigned char mask
, unsigned char data
)
111 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
115 mutex_lock(&chip
->io_lock
);
116 ret
= pm860x_read_device(i2c
, reg
, 1, &value
);
121 ret
= pm860x_write_device(i2c
, reg
, 1, &value
);
123 mutex_unlock(&chip
->io_lock
);
126 EXPORT_SYMBOL(pm860x_set_bits
);
129 static const struct i2c_device_id pm860x_id_table
[] = {
133 MODULE_DEVICE_TABLE(i2c
, pm860x_id_table
);
135 static int verify_addr(struct i2c_client
*i2c
)
137 unsigned short addr_8607
[] = {0x30, 0x34};
138 unsigned short addr_8606
[] = {0x10, 0x11};
143 size
= ARRAY_SIZE(addr_8606
);
144 for (i
= 0; i
< size
; i
++) {
145 if (i2c
->addr
== *(addr_8606
+ i
))
148 size
= ARRAY_SIZE(addr_8607
);
149 for (i
= 0; i
< size
; i
++) {
150 if (i2c
->addr
== *(addr_8607
+ i
))
156 static int __devinit
pm860x_probe(struct i2c_client
*client
,
157 const struct i2c_device_id
*id
)
159 struct pm860x_platform_data
*pdata
= client
->dev
.platform_data
;
160 static struct pm860x_chip
*chip
;
161 struct i2c_board_info i2c_info
= {
163 .platform_data
= client
->dev
.platform_data
,
165 int addr_c
, found_companion
= 0;
168 pr_info("No platform data in %s!\n", __func__
);
173 * Both client and companion client shares same platform driver.
174 * Driver distinguishes them by pdata->companion_addr.
175 * pdata->companion_addr is only assigned if companion chip exists.
176 * At the same time, the companion_addr shouldn't equal to client
179 addr_c
= pdata
->companion_addr
;
180 if (addr_c
&& (addr_c
!= client
->addr
)) {
181 i2c_info
.addr
= addr_c
;
185 if (found_companion
|| (addr_c
== 0)) {
186 chip
= kzalloc(sizeof(struct pm860x_chip
), GFP_KERNEL
);
190 chip
->id
= verify_addr(client
);
191 chip
->companion_addr
= addr_c
;
192 chip
->client
= client
;
193 i2c_set_clientdata(client
, chip
);
194 chip
->dev
= &client
->dev
;
195 mutex_init(&chip
->io_lock
);
196 dev_set_drvdata(chip
->dev
, chip
);
198 if (found_companion
) {
200 * If this driver is built in, probe function is
202 * If this driver is built as module, the next probe
203 * function is called after the first one finished.
205 chip
->companion
= i2c_new_device(client
->adapter
,
211 * If companion chip existes, it's called by companion probe.
212 * If there's no companion chip, it's called by client probe.
214 if ((addr_c
== 0) || (addr_c
== client
->addr
)) {
215 chip
->companion
= client
;
216 i2c_set_clientdata(chip
->companion
, chip
);
217 pm860x_device_init(chip
, pdata
);
222 static int __devexit
pm860x_remove(struct i2c_client
*client
)
224 struct pm860x_chip
*chip
= i2c_get_clientdata(client
);
227 * If companion existes, companion client is removed first.
228 * Because companion client is registered last and removed first.
230 if (chip
->companion_addr
== client
->addr
)
232 pm860x_device_exit(chip
);
233 i2c_unregister_device(chip
->companion
);
234 i2c_set_clientdata(chip
->companion
, NULL
);
235 i2c_set_clientdata(chip
->client
, NULL
);
240 static struct i2c_driver pm860x_driver
= {
243 .owner
= THIS_MODULE
,
245 .probe
= pm860x_probe
,
246 .remove
= __devexit_p(pm860x_remove
),
247 .id_table
= pm860x_id_table
,
250 static int __init
pm860x_i2c_init(void)
253 ret
= i2c_add_driver(&pm860x_driver
);
255 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret
);
258 subsys_initcall(pm860x_i2c_init
);
260 static void __exit
pm860x_i2c_exit(void)
262 i2c_del_driver(&pm860x_driver
);
264 module_exit(pm860x_i2c_exit
);
266 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
267 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
268 MODULE_LICENSE("GPL");