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>
16 #include <linux/slab.h>
18 static inline int pm860x_read_device(struct i2c_client
*i2c
,
19 int reg
, int bytes
, void *dest
)
24 data
= (unsigned char)reg
;
25 ret
= i2c_master_send(i2c
, &data
, 1);
29 ret
= i2c_master_recv(i2c
, dest
, bytes
);
35 static inline int pm860x_write_device(struct i2c_client
*i2c
,
36 int reg
, int bytes
, void *src
)
38 unsigned char buf
[bytes
+ 1];
41 buf
[0] = (unsigned char)reg
;
42 memcpy(&buf
[1], src
, bytes
);
44 ret
= i2c_master_send(i2c
, buf
, bytes
+ 1);
50 int pm860x_reg_read(struct i2c_client
*i2c
, int reg
)
52 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
56 mutex_lock(&chip
->io_lock
);
57 ret
= pm860x_read_device(i2c
, reg
, 1, &data
);
58 mutex_unlock(&chip
->io_lock
);
65 EXPORT_SYMBOL(pm860x_reg_read
);
67 int pm860x_reg_write(struct i2c_client
*i2c
, int reg
,
70 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
73 mutex_lock(&chip
->io_lock
);
74 ret
= pm860x_write_device(i2c
, reg
, 1, &data
);
75 mutex_unlock(&chip
->io_lock
);
79 EXPORT_SYMBOL(pm860x_reg_write
);
81 int pm860x_bulk_read(struct i2c_client
*i2c
, int reg
,
82 int count
, unsigned char *buf
)
84 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
87 mutex_lock(&chip
->io_lock
);
88 ret
= pm860x_read_device(i2c
, reg
, count
, buf
);
89 mutex_unlock(&chip
->io_lock
);
93 EXPORT_SYMBOL(pm860x_bulk_read
);
95 int pm860x_bulk_write(struct i2c_client
*i2c
, int reg
,
96 int count
, unsigned char *buf
)
98 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
101 mutex_lock(&chip
->io_lock
);
102 ret
= pm860x_write_device(i2c
, reg
, count
, buf
);
103 mutex_unlock(&chip
->io_lock
);
107 EXPORT_SYMBOL(pm860x_bulk_write
);
109 int pm860x_set_bits(struct i2c_client
*i2c
, int reg
,
110 unsigned char mask
, unsigned char data
)
112 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
116 mutex_lock(&chip
->io_lock
);
117 ret
= pm860x_read_device(i2c
, reg
, 1, &value
);
122 ret
= pm860x_write_device(i2c
, reg
, 1, &value
);
124 mutex_unlock(&chip
->io_lock
);
127 EXPORT_SYMBOL(pm860x_set_bits
);
130 static const struct i2c_device_id pm860x_id_table
[] = {
134 MODULE_DEVICE_TABLE(i2c
, pm860x_id_table
);
136 static int verify_addr(struct i2c_client
*i2c
)
138 unsigned short addr_8607
[] = {0x30, 0x34};
139 unsigned short addr_8606
[] = {0x10, 0x11};
144 size
= ARRAY_SIZE(addr_8606
);
145 for (i
= 0; i
< size
; i
++) {
146 if (i2c
->addr
== *(addr_8606
+ i
))
149 size
= ARRAY_SIZE(addr_8607
);
150 for (i
= 0; i
< size
; i
++) {
151 if (i2c
->addr
== *(addr_8607
+ i
))
157 static int __devinit
pm860x_probe(struct i2c_client
*client
,
158 const struct i2c_device_id
*id
)
160 struct pm860x_platform_data
*pdata
= client
->dev
.platform_data
;
161 struct pm860x_chip
*chip
;
164 pr_info("No platform data in %s!\n", __func__
);
168 chip
= kzalloc(sizeof(struct pm860x_chip
), GFP_KERNEL
);
172 chip
->id
= verify_addr(client
);
173 chip
->client
= client
;
174 i2c_set_clientdata(client
, chip
);
175 chip
->dev
= &client
->dev
;
176 mutex_init(&chip
->io_lock
);
177 dev_set_drvdata(chip
->dev
, chip
);
180 * Both client and companion client shares same platform driver.
181 * Driver distinguishes them by pdata->companion_addr.
182 * pdata->companion_addr is only assigned if companion chip exists.
183 * At the same time, the companion_addr shouldn't equal to client
186 if (pdata
->companion_addr
&& (pdata
->companion_addr
!= client
->addr
)) {
187 chip
->companion_addr
= pdata
->companion_addr
;
188 chip
->companion
= i2c_new_dummy(chip
->client
->adapter
,
189 chip
->companion_addr
);
190 i2c_set_clientdata(chip
->companion
, chip
);
193 pm860x_device_init(chip
, pdata
);
197 static int __devexit
pm860x_remove(struct i2c_client
*client
)
199 struct pm860x_chip
*chip
= i2c_get_clientdata(client
);
201 pm860x_device_exit(chip
);
202 i2c_unregister_device(chip
->companion
);
207 static struct i2c_driver pm860x_driver
= {
210 .owner
= THIS_MODULE
,
212 .probe
= pm860x_probe
,
213 .remove
= __devexit_p(pm860x_remove
),
214 .id_table
= pm860x_id_table
,
217 static int __init
pm860x_i2c_init(void)
220 ret
= i2c_add_driver(&pm860x_driver
);
222 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret
);
225 subsys_initcall(pm860x_i2c_init
);
227 static void __exit
pm860x_i2c_exit(void)
229 i2c_del_driver(&pm860x_driver
);
231 module_exit(pm860x_i2c_exit
);
233 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
234 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
235 MODULE_LICENSE("GPL");