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 struct pm860x_chip
*chip
;
163 pr_info("No platform data in %s!\n", __func__
);
167 chip
= kzalloc(sizeof(struct pm860x_chip
), GFP_KERNEL
);
171 chip
->id
= verify_addr(client
);
172 chip
->client
= client
;
173 i2c_set_clientdata(client
, chip
);
174 chip
->dev
= &client
->dev
;
175 mutex_init(&chip
->io_lock
);
176 dev_set_drvdata(chip
->dev
, chip
);
179 * Both client and companion client shares same platform driver.
180 * Driver distinguishes them by pdata->companion_addr.
181 * pdata->companion_addr is only assigned if companion chip exists.
182 * At the same time, the companion_addr shouldn't equal to client
185 if (pdata
->companion_addr
&& (pdata
->companion_addr
!= client
->addr
)) {
186 chip
->companion_addr
= pdata
->companion_addr
;
187 chip
->companion
= i2c_new_dummy(chip
->client
->adapter
,
188 chip
->companion_addr
);
189 i2c_set_clientdata(chip
->companion
, chip
);
192 pm860x_device_init(chip
, pdata
);
196 static int __devexit
pm860x_remove(struct i2c_client
*client
)
198 struct pm860x_chip
*chip
= i2c_get_clientdata(client
);
200 pm860x_device_exit(chip
);
201 i2c_unregister_device(chip
->companion
);
202 i2c_set_clientdata(chip
->companion
, NULL
);
203 i2c_set_clientdata(chip
->client
, NULL
);
208 static struct i2c_driver pm860x_driver
= {
211 .owner
= THIS_MODULE
,
213 .probe
= pm860x_probe
,
214 .remove
= __devexit_p(pm860x_remove
),
215 .id_table
= pm860x_id_table
,
218 static int __init
pm860x_i2c_init(void)
221 ret
= i2c_add_driver(&pm860x_driver
);
223 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret
);
226 subsys_initcall(pm860x_i2c_init
);
228 static void __exit
pm860x_i2c_exit(void)
230 i2c_del_driver(&pm860x_driver
);
232 module_exit(pm860x_i2c_exit
);
234 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
235 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
236 MODULE_LICENSE("GPL");