2 * Copyright (C) 2012 Google, Inc
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Expose an I2C passthrough to the ChromeOS EC.
22 #include <linux/module.h>
23 #include <linux/i2c.h>
24 #include <linux/mfd/chromeos_ec.h>
25 #include <linux/mfd/chromeos_ec_commands.h>
26 #include <linux/of_i2c.h>
27 #include <linux/platform_device.h>
28 #include <linux/slab.h>
30 struct ec_i2c_device {
32 struct i2c_adapter adap;
33 struct chromeos_ec_device *ec;
36 #define CHECK_I2C_WR(num, length) \
37 (((msgs[num].flags & I2C_M_RD) == 0) && (msgs[num].len == length))
39 #define CHECK_I2C_RD(num, length) \
40 ((msgs[num].flags & I2C_M_RD) && (msgs[num].len == length))
42 /* Standard I2C address for smart batteries */
43 #define SBS_I2C_ADDR 0xB
45 static int ec_forward_to_sbs(struct i2c_adapter *adap, struct i2c_msg msgs[],
48 struct ec_i2c_device *bus = adap->algo_data;
50 /* Battery device probing */
51 if ((num == 1) && (msgs[0].len == 0))
52 return bus->ec->command_sendrecv(bus->ec, EC_CMD_SB_READ_WORD,
53 msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len);
54 /* Read a word-sized register */
55 if ((num == 1) && CHECK_I2C_WR(0, 3))
56 return bus->ec->command_send(bus->ec, EC_CMD_SB_WRITE_WORD,
57 msgs[0].buf, msgs[0].len);
58 /* Write a word-sized register */
59 if ((num == 2) && CHECK_I2C_WR(0, 1) && CHECK_I2C_RD(1, 2))
60 return bus->ec->command_sendrecv(bus->ec, EC_CMD_SB_READ_WORD,
61 msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len);
62 /* Retrieve string data length */
63 if ((num == 2) && CHECK_I2C_WR(0, 1) && CHECK_I2C_RD(1, 1)) {
64 msgs[1].buf[0] = I2C_SMBUS_BLOCK_MAX;
67 /* Read string data */
68 if ((num == 2) && CHECK_I2C_WR(0, 1) &&
69 CHECK_I2C_RD(1, I2C_SMBUS_BLOCK_MAX)) {
70 char tmpblock[I2C_SMBUS_BLOCK_MAX + 1];
71 int ret = bus->ec->command_sendrecv(bus->ec,
72 EC_CMD_SB_READ_BLOCK, msgs[0].buf, msgs[0].len,
73 tmpblock, I2C_SMBUS_BLOCK_MAX);
74 tmpblock[I2C_SMBUS_BLOCK_MAX] = 0;
75 /* real string length */
76 msgs[1].buf[0] = strlen(tmpblock);
77 strlcpy(&msgs[1].buf[1], tmpblock, msgs[1].len);
84 static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
87 struct ec_i2c_device *bus = adap->algo_data;
89 if (num && (i2c_msgs[0].addr == SBS_I2C_ADDR))
90 return ec_forward_to_sbs(adap, i2c_msgs, num);
92 return bus->ec->command_i2c(bus->ec, i2c_msgs, num);
95 static u32 ec_i2c_functionality(struct i2c_adapter *adap)
97 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
100 static const struct i2c_algorithm ec_i2c_algorithm = {
101 .master_xfer = ec_i2c_xfer,
102 .functionality = ec_i2c_functionality,
105 static int __devinit ec_i2c_probe(struct platform_device *pdev)
107 struct chromeos_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
108 struct device *dev = ec->dev;
109 struct ec_i2c_device *bus = NULL;
112 dev_dbg(dev, "EC I2C pass-through probing\n");
114 bus = kzalloc(sizeof(*bus), GFP_KERNEL);
117 dev_err(dev, "cannot allocate bus device\n");
124 bus->adap.owner = THIS_MODULE;
125 bus->adap.retries = 3;
127 strlcpy(bus->adap.name, "cros_ec_i2c", sizeof(bus->adap.name));
128 bus->adap.algo = &ec_i2c_algorithm;
129 bus->adap.algo_data = bus;
130 bus->adap.dev.parent = &pdev->dev;
131 bus->adap.dev.of_node = of_find_compatible_node(dev->of_node, NULL,
132 "google,cros_ec-i2c");
133 err = i2c_add_adapter(&bus->adap);
135 dev_err(dev, "cannot register i2c adapter\n");
138 platform_set_drvdata(pdev, bus);
140 dev_info(&pdev->dev, "%s: Chrome EC I2C pass-through adapter\n",
143 of_i2c_register_devices(&bus->adap);
152 static int __exit ec_i2c_remove(struct platform_device *dev)
154 struct ec_i2c_device *bus = platform_get_drvdata(dev);
156 platform_set_drvdata(dev, NULL);
158 i2c_del_adapter(&bus->adap);
164 static struct platform_driver ec_i2c_driver = {
165 .probe = ec_i2c_probe,
166 .remove = __exit_p(ec_i2c_remove),
168 .name = "cros_ec-i2c",
173 module_platform_driver(ec_i2c_driver);
175 MODULE_LICENSE("GPL");
176 MODULE_DESCRIPTION("EC I2C pass-through driver");
177 MODULE_ALIAS("platform:cros_ec-i2c");