xref: /openbmc/linux/drivers/mfd/88pm860x-i2c.c (revision bbd51b1f)
1bbd51b1fSHaojian Zhuang /*
2bbd51b1fSHaojian Zhuang  * I2C driver for Marvell 88PM8607
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/platform_device.h>
14bbd51b1fSHaojian Zhuang #include <linux/i2c.h>
15bbd51b1fSHaojian Zhuang #include <linux/mfd/88pm8607.h>
16bbd51b1fSHaojian Zhuang 
17bbd51b1fSHaojian Zhuang static inline int pm8607_read_device(struct pm8607_chip *chip,
18bbd51b1fSHaojian Zhuang 				     int reg, int bytes, void *dest)
19bbd51b1fSHaojian Zhuang {
20bbd51b1fSHaojian Zhuang 	struct i2c_client *i2c = chip->client;
21bbd51b1fSHaojian Zhuang 	unsigned char data;
22bbd51b1fSHaojian Zhuang 	int ret;
23bbd51b1fSHaojian Zhuang 
24bbd51b1fSHaojian Zhuang 	data = (unsigned char)reg;
25bbd51b1fSHaojian Zhuang 	ret = i2c_master_send(i2c, &data, 1);
26bbd51b1fSHaojian Zhuang 	if (ret < 0)
27bbd51b1fSHaojian Zhuang 		return ret;
28bbd51b1fSHaojian Zhuang 
29bbd51b1fSHaojian Zhuang 	ret = i2c_master_recv(i2c, dest, bytes);
30bbd51b1fSHaojian Zhuang 	if (ret < 0)
31bbd51b1fSHaojian Zhuang 		return ret;
32bbd51b1fSHaojian Zhuang 	return 0;
33bbd51b1fSHaojian Zhuang }
34bbd51b1fSHaojian Zhuang 
35bbd51b1fSHaojian Zhuang static inline int pm8607_write_device(struct pm8607_chip *chip,
36bbd51b1fSHaojian Zhuang 				      int reg, int bytes, void *src)
37bbd51b1fSHaojian Zhuang {
38bbd51b1fSHaojian Zhuang 	struct i2c_client *i2c = chip->client;
39bbd51b1fSHaojian Zhuang 	unsigned char buf[bytes + 1];
40bbd51b1fSHaojian Zhuang 	int ret;
41bbd51b1fSHaojian Zhuang 
42bbd51b1fSHaojian Zhuang 	buf[0] = (unsigned char)reg;
43bbd51b1fSHaojian Zhuang 	memcpy(&buf[1], src, bytes);
44bbd51b1fSHaojian Zhuang 
45bbd51b1fSHaojian Zhuang 	ret = i2c_master_send(i2c, buf, bytes + 1);
46bbd51b1fSHaojian Zhuang 	if (ret < 0)
47bbd51b1fSHaojian Zhuang 		return ret;
48bbd51b1fSHaojian Zhuang 	return 0;
49bbd51b1fSHaojian Zhuang }
50bbd51b1fSHaojian Zhuang 
51bbd51b1fSHaojian Zhuang int pm8607_reg_read(struct pm8607_chip *chip, int reg)
52bbd51b1fSHaojian Zhuang {
53bbd51b1fSHaojian Zhuang 	unsigned char data;
54bbd51b1fSHaojian Zhuang 	int ret;
55bbd51b1fSHaojian Zhuang 
56bbd51b1fSHaojian Zhuang 	mutex_lock(&chip->io_lock);
57bbd51b1fSHaojian Zhuang 	ret = chip->read(chip, reg, 1, &data);
58bbd51b1fSHaojian Zhuang 	mutex_unlock(&chip->io_lock);
59bbd51b1fSHaojian Zhuang 
60bbd51b1fSHaojian Zhuang 	if (ret < 0)
61bbd51b1fSHaojian Zhuang 		return ret;
62bbd51b1fSHaojian Zhuang 	else
63bbd51b1fSHaojian Zhuang 		return (int)data;
64bbd51b1fSHaojian Zhuang }
65bbd51b1fSHaojian Zhuang EXPORT_SYMBOL(pm8607_reg_read);
66bbd51b1fSHaojian Zhuang 
67bbd51b1fSHaojian Zhuang int pm8607_reg_write(struct pm8607_chip *chip, int reg,
68bbd51b1fSHaojian Zhuang 		     unsigned char data)
69bbd51b1fSHaojian Zhuang {
70bbd51b1fSHaojian Zhuang 	int ret;
71bbd51b1fSHaojian Zhuang 
72bbd51b1fSHaojian Zhuang 	mutex_lock(&chip->io_lock);
73bbd51b1fSHaojian Zhuang 	ret = chip->write(chip, reg, 1, &data);
74bbd51b1fSHaojian Zhuang 	mutex_unlock(&chip->io_lock);
75bbd51b1fSHaojian Zhuang 
76bbd51b1fSHaojian Zhuang 	return ret;
77bbd51b1fSHaojian Zhuang }
78bbd51b1fSHaojian Zhuang EXPORT_SYMBOL(pm8607_reg_write);
79bbd51b1fSHaojian Zhuang 
80bbd51b1fSHaojian Zhuang int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
81bbd51b1fSHaojian Zhuang 		     int count, unsigned char *buf)
82bbd51b1fSHaojian Zhuang {
83bbd51b1fSHaojian Zhuang 	int ret;
84bbd51b1fSHaojian Zhuang 
85bbd51b1fSHaojian Zhuang 	mutex_lock(&chip->io_lock);
86bbd51b1fSHaojian Zhuang 	ret = chip->read(chip, reg, count, buf);
87bbd51b1fSHaojian Zhuang 	mutex_unlock(&chip->io_lock);
88bbd51b1fSHaojian Zhuang 
89bbd51b1fSHaojian Zhuang 	return ret;
90bbd51b1fSHaojian Zhuang }
91bbd51b1fSHaojian Zhuang EXPORT_SYMBOL(pm8607_bulk_read);
92bbd51b1fSHaojian Zhuang 
93bbd51b1fSHaojian Zhuang int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
94bbd51b1fSHaojian Zhuang 		      int count, unsigned char *buf)
95bbd51b1fSHaojian Zhuang {
96bbd51b1fSHaojian Zhuang 	int ret;
97bbd51b1fSHaojian Zhuang 
98bbd51b1fSHaojian Zhuang 	mutex_lock(&chip->io_lock);
99bbd51b1fSHaojian Zhuang 	ret = chip->write(chip, reg, count, buf);
100bbd51b1fSHaojian Zhuang 	mutex_unlock(&chip->io_lock);
101bbd51b1fSHaojian Zhuang 
102bbd51b1fSHaojian Zhuang 	return ret;
103bbd51b1fSHaojian Zhuang }
104bbd51b1fSHaojian Zhuang EXPORT_SYMBOL(pm8607_bulk_write);
105bbd51b1fSHaojian Zhuang 
106bbd51b1fSHaojian Zhuang int pm8607_set_bits(struct pm8607_chip *chip, int reg,
107bbd51b1fSHaojian Zhuang 		    unsigned char mask, unsigned char data)
108bbd51b1fSHaojian Zhuang {
109bbd51b1fSHaojian Zhuang 	unsigned char value;
110bbd51b1fSHaojian Zhuang 	int ret;
111bbd51b1fSHaojian Zhuang 
112bbd51b1fSHaojian Zhuang 	mutex_lock(&chip->io_lock);
113bbd51b1fSHaojian Zhuang 	ret = chip->read(chip, reg, 1, &value);
114bbd51b1fSHaojian Zhuang 	if (ret < 0)
115bbd51b1fSHaojian Zhuang 		goto out;
116bbd51b1fSHaojian Zhuang 	value &= ~mask;
117bbd51b1fSHaojian Zhuang 	value |= data;
118bbd51b1fSHaojian Zhuang 	ret = chip->write(chip, reg, 1, &value);
119bbd51b1fSHaojian Zhuang out:
120bbd51b1fSHaojian Zhuang 	mutex_unlock(&chip->io_lock);
121bbd51b1fSHaojian Zhuang 	return ret;
122bbd51b1fSHaojian Zhuang }
123bbd51b1fSHaojian Zhuang EXPORT_SYMBOL(pm8607_set_bits);
124bbd51b1fSHaojian Zhuang 
125bbd51b1fSHaojian Zhuang 
126bbd51b1fSHaojian Zhuang static const struct i2c_device_id pm860x_id_table[] = {
127bbd51b1fSHaojian Zhuang 	{ "88PM8607", 0 },
128bbd51b1fSHaojian Zhuang 	{}
129bbd51b1fSHaojian Zhuang };
130bbd51b1fSHaojian Zhuang MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
131bbd51b1fSHaojian Zhuang 
132bbd51b1fSHaojian Zhuang static int __devinit pm860x_probe(struct i2c_client *client,
133bbd51b1fSHaojian Zhuang 				  const struct i2c_device_id *id)
134bbd51b1fSHaojian Zhuang {
135bbd51b1fSHaojian Zhuang 	struct pm8607_platform_data *pdata = client->dev.platform_data;
136bbd51b1fSHaojian Zhuang 	struct pm8607_chip *chip;
137bbd51b1fSHaojian Zhuang 	int ret;
138bbd51b1fSHaojian Zhuang 
139bbd51b1fSHaojian Zhuang 	chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
140bbd51b1fSHaojian Zhuang 	if (chip == NULL)
141bbd51b1fSHaojian Zhuang 		return -ENOMEM;
142bbd51b1fSHaojian Zhuang 
143bbd51b1fSHaojian Zhuang 	chip->client = client;
144bbd51b1fSHaojian Zhuang 	chip->dev = &client->dev;
145bbd51b1fSHaojian Zhuang 	chip->read = pm8607_read_device;
146bbd51b1fSHaojian Zhuang 	chip->write = pm8607_write_device;
147bbd51b1fSHaojian Zhuang 	memcpy(&chip->id, id, sizeof(struct i2c_device_id));
148bbd51b1fSHaojian Zhuang 	i2c_set_clientdata(client, chip);
149bbd51b1fSHaojian Zhuang 
150bbd51b1fSHaojian Zhuang 	mutex_init(&chip->io_lock);
151bbd51b1fSHaojian Zhuang 	dev_set_drvdata(chip->dev, chip);
152bbd51b1fSHaojian Zhuang 
153bbd51b1fSHaojian Zhuang 	ret = pm860x_device_init(chip, pdata);
154bbd51b1fSHaojian Zhuang 	if (ret < 0)
155bbd51b1fSHaojian Zhuang 		goto out;
156bbd51b1fSHaojian Zhuang 
157bbd51b1fSHaojian Zhuang 
158bbd51b1fSHaojian Zhuang 	return 0;
159bbd51b1fSHaojian Zhuang 
160bbd51b1fSHaojian Zhuang out:
161bbd51b1fSHaojian Zhuang 	i2c_set_clientdata(client, NULL);
162bbd51b1fSHaojian Zhuang 	kfree(chip);
163bbd51b1fSHaojian Zhuang 	return ret;
164bbd51b1fSHaojian Zhuang }
165bbd51b1fSHaojian Zhuang 
166bbd51b1fSHaojian Zhuang static int __devexit pm860x_remove(struct i2c_client *client)
167bbd51b1fSHaojian Zhuang {
168bbd51b1fSHaojian Zhuang 	struct pm8607_chip *chip = i2c_get_clientdata(client);
169bbd51b1fSHaojian Zhuang 
170bbd51b1fSHaojian Zhuang 	kfree(chip);
171bbd51b1fSHaojian Zhuang 	return 0;
172bbd51b1fSHaojian Zhuang }
173bbd51b1fSHaojian Zhuang 
174bbd51b1fSHaojian Zhuang static struct i2c_driver pm860x_driver = {
175bbd51b1fSHaojian Zhuang 	.driver	= {
176bbd51b1fSHaojian Zhuang 		.name	= "88PM860x",
177bbd51b1fSHaojian Zhuang 		.owner	= THIS_MODULE,
178bbd51b1fSHaojian Zhuang 	},
179bbd51b1fSHaojian Zhuang 	.probe		= pm860x_probe,
180bbd51b1fSHaojian Zhuang 	.remove		= __devexit_p(pm860x_remove),
181bbd51b1fSHaojian Zhuang 	.id_table	= pm860x_id_table,
182bbd51b1fSHaojian Zhuang };
183bbd51b1fSHaojian Zhuang 
184bbd51b1fSHaojian Zhuang static int __init pm860x_i2c_init(void)
185bbd51b1fSHaojian Zhuang {
186bbd51b1fSHaojian Zhuang 	int ret;
187bbd51b1fSHaojian Zhuang 	ret = i2c_add_driver(&pm860x_driver);
188bbd51b1fSHaojian Zhuang 	if (ret != 0)
189bbd51b1fSHaojian Zhuang 		pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
190bbd51b1fSHaojian Zhuang 	return ret;
191bbd51b1fSHaojian Zhuang }
192bbd51b1fSHaojian Zhuang subsys_initcall(pm860x_i2c_init);
193bbd51b1fSHaojian Zhuang 
194bbd51b1fSHaojian Zhuang static void __exit pm860x_i2c_exit(void)
195bbd51b1fSHaojian Zhuang {
196bbd51b1fSHaojian Zhuang 	i2c_del_driver(&pm860x_driver);
197bbd51b1fSHaojian Zhuang }
198bbd51b1fSHaojian Zhuang module_exit(pm860x_i2c_exit);
199bbd51b1fSHaojian Zhuang 
200bbd51b1fSHaojian Zhuang MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
201bbd51b1fSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
202bbd51b1fSHaojian Zhuang MODULE_LICENSE("GPL");
203