Commit | Line | Data |
---|---|---|
9d230c9e DA |
1 | /* |
2 | * Copyright (C) 2013 Google, Inc | |
3 | * | |
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. | |
8 | * | |
9 | * Expose an I2C passthrough to the ChromeOS EC. | |
10 | */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/i2c.h> | |
14 | #include <linux/mfd/cros_ec.h> | |
15 | #include <linux/mfd/cros_ec_commands.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <linux/slab.h> | |
18 | ||
97720706 DB |
19 | #define I2C_MAX_RETRIES 3 |
20 | ||
9d230c9e DA |
21 | /** |
22 | * struct ec_i2c_device - Driver data for I2C tunnel | |
23 | * | |
24 | * @dev: Device node | |
25 | * @adap: I2C adapter | |
26 | * @ec: Pointer to EC device | |
27 | * @remote_bus: The EC bus number we tunnel to on the other side. | |
28 | * @request_buf: Buffer for transmitting data; we expect most transfers to fit. | |
29 | * @response_buf: Buffer for receiving data; we expect most transfers to fit. | |
30 | */ | |
31 | ||
32 | struct ec_i2c_device { | |
33 | struct device *dev; | |
34 | struct i2c_adapter adap; | |
35 | struct cros_ec_device *ec; | |
36 | ||
37 | u16 remote_bus; | |
38 | ||
39 | u8 request_buf[256]; | |
40 | u8 response_buf[256]; | |
41 | }; | |
42 | ||
43 | /** | |
44 | * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message | |
45 | * | |
46 | * @i2c_msgs: The i2c messages to read | |
47 | * @num: The number of i2c messages. | |
48 | * | |
49 | * Returns the number of bytes the messages will take up. | |
50 | */ | |
51 | static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num) | |
52 | { | |
53 | int i; | |
54 | int size; | |
55 | ||
56 | size = sizeof(struct ec_params_i2c_passthru); | |
57 | size += num * sizeof(struct ec_params_i2c_passthru_msg); | |
58 | for (i = 0; i < num; i++) | |
59 | if (!(i2c_msgs[i].flags & I2C_M_RD)) | |
60 | size += i2c_msgs[i].len; | |
61 | ||
62 | return size; | |
63 | } | |
64 | ||
65 | /** | |
66 | * ec_i2c_construct_message - construct a message to go to the EC | |
67 | * | |
68 | * This function effectively stuffs the standard i2c_msg format of Linux into | |
69 | * a format that the EC understands. | |
70 | * | |
71 | * @buf: The buffer to fill. We assume that the buffer is big enough. | |
72 | * @i2c_msgs: The i2c messages to read. | |
73 | * @num: The number of i2c messages. | |
74 | * @bus_num: The remote bus number we want to talk to. | |
75 | * | |
76 | * Returns 0 or a negative error number. | |
77 | */ | |
78 | static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[], | |
79 | int num, u16 bus_num) | |
80 | { | |
81 | struct ec_params_i2c_passthru *params; | |
82 | u8 *out_data; | |
83 | int i; | |
84 | ||
85 | out_data = buf + sizeof(struct ec_params_i2c_passthru) + | |
86 | num * sizeof(struct ec_params_i2c_passthru_msg); | |
87 | ||
88 | params = (struct ec_params_i2c_passthru *)buf; | |
89 | params->port = bus_num; | |
90 | params->num_msgs = num; | |
91 | for (i = 0; i < num; i++) { | |
92 | const struct i2c_msg *i2c_msg = &i2c_msgs[i]; | |
93 | struct ec_params_i2c_passthru_msg *msg = ¶ms->msg[i]; | |
94 | ||
95 | msg->len = i2c_msg->len; | |
96 | msg->addr_flags = i2c_msg->addr; | |
97 | ||
98 | if (i2c_msg->flags & I2C_M_TEN) | |
d8e0a86f | 99 | return -EINVAL; |
9d230c9e DA |
100 | |
101 | if (i2c_msg->flags & I2C_M_RD) { | |
102 | msg->addr_flags |= EC_I2C_FLAG_READ; | |
103 | } else { | |
104 | memcpy(out_data, i2c_msg->buf, msg->len); | |
105 | out_data += msg->len; | |
106 | } | |
107 | } | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | /** | |
113 | * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response | |
114 | * | |
115 | * @i2c_msgs: The i2c messages to to fill up. | |
116 | * @num: The number of i2c messages expected. | |
117 | * | |
118 | * Returns the number of response bytes expeced. | |
119 | */ | |
120 | static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num) | |
121 | { | |
122 | int size; | |
123 | int i; | |
124 | ||
125 | size = sizeof(struct ec_response_i2c_passthru); | |
126 | for (i = 0; i < num; i++) | |
127 | if (i2c_msgs[i].flags & I2C_M_RD) | |
128 | size += i2c_msgs[i].len; | |
129 | ||
130 | return size; | |
131 | } | |
132 | ||
133 | /** | |
134 | * ec_i2c_parse_response - Parse a response from the EC | |
135 | * | |
136 | * We'll take the EC's response and copy it back into msgs. | |
137 | * | |
138 | * @buf: The buffer to parse. | |
139 | * @i2c_msgs: The i2c messages to to fill up. | |
140 | * @num: The number of i2c messages; will be modified to include the actual | |
141 | * number received. | |
142 | * | |
143 | * Returns 0 or a negative error number. | |
144 | */ | |
145 | static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[], | |
146 | int *num) | |
147 | { | |
148 | const struct ec_response_i2c_passthru *resp; | |
149 | const u8 *in_data; | |
150 | int i; | |
151 | ||
152 | in_data = buf + sizeof(struct ec_response_i2c_passthru); | |
153 | ||
154 | resp = (const struct ec_response_i2c_passthru *)buf; | |
155 | if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT) | |
156 | return -ETIMEDOUT; | |
157 | else if (resp->i2c_status & EC_I2C_STATUS_ERROR) | |
158 | return -EREMOTEIO; | |
159 | ||
160 | /* Other side could send us back fewer messages, but not more */ | |
161 | if (resp->num_msgs > *num) | |
162 | return -EPROTO; | |
163 | *num = resp->num_msgs; | |
164 | ||
165 | for (i = 0; i < *num; i++) { | |
166 | struct i2c_msg *i2c_msg = &i2c_msgs[i]; | |
167 | ||
168 | if (i2c_msgs[i].flags & I2C_M_RD) { | |
169 | memcpy(i2c_msg->buf, in_data, i2c_msg->len); | |
170 | in_data += i2c_msg->len; | |
171 | } | |
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], | |
178 | int num) | |
179 | { | |
180 | struct ec_i2c_device *bus = adap->algo_data; | |
181 | struct device *dev = bus->dev; | |
182 | const u16 bus_num = bus->remote_bus; | |
183 | int request_len; | |
184 | int response_len; | |
9d230c9e | 185 | int result; |
1b84f2a4 | 186 | struct cros_ec_command msg = { }; |
9d230c9e DA |
187 | |
188 | request_len = ec_i2c_count_message(i2c_msgs, num); | |
189 | if (request_len < 0) { | |
190 | dev_warn(dev, "Error constructing message %d\n", request_len); | |
1b84f2a4 | 191 | return request_len; |
9d230c9e | 192 | } |
1b84f2a4 | 193 | |
9d230c9e DA |
194 | response_len = ec_i2c_count_response(i2c_msgs, num); |
195 | if (response_len < 0) { | |
196 | /* Unexpected; no errors should come when NULL response */ | |
197 | dev_warn(dev, "Error preparing response %d\n", response_len); | |
1b84f2a4 | 198 | return response_len; |
9d230c9e DA |
199 | } |
200 | ||
1b84f2a4 | 201 | result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); |
d8e0a86f | 202 | if (result) |
1b84f2a4 | 203 | return result; |
5799f95a BR |
204 | |
205 | msg.version = 0; | |
206 | msg.command = EC_CMD_I2C_PASSTHRU; | |
5799f95a | 207 | msg.outsize = request_len; |
5799f95a BR |
208 | msg.insize = response_len; |
209 | ||
a6551a76 | 210 | result = cros_ec_cmd_xfer(bus->ec, &msg); |
12ebc8a5 | 211 | if (result < 0) |
1b84f2a4 | 212 | return result; |
9d230c9e | 213 | |
1b84f2a4 | 214 | result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); |
9d230c9e | 215 | if (result < 0) |
1b84f2a4 | 216 | return result; |
9d230c9e DA |
217 | |
218 | /* Indicate success by saying how many messages were sent */ | |
1b84f2a4 | 219 | return num; |
9d230c9e DA |
220 | } |
221 | ||
222 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) | |
223 | { | |
224 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | |
225 | } | |
226 | ||
227 | static const struct i2c_algorithm ec_i2c_algorithm = { | |
228 | .master_xfer = ec_i2c_xfer, | |
229 | .functionality = ec_i2c_functionality, | |
230 | }; | |
231 | ||
232 | static int ec_i2c_probe(struct platform_device *pdev) | |
233 | { | |
234 | struct device_node *np = pdev->dev.of_node; | |
235 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | |
236 | struct device *dev = &pdev->dev; | |
237 | struct ec_i2c_device *bus = NULL; | |
238 | u32 remote_bus; | |
239 | int err; | |
240 | ||
5799f95a | 241 | if (!ec->cmd_xfer) { |
9d230c9e DA |
242 | dev_err(dev, "Missing sendrecv\n"); |
243 | return -EINVAL; | |
244 | } | |
245 | ||
246 | bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); | |
247 | if (bus == NULL) | |
248 | return -ENOMEM; | |
249 | ||
250 | err = of_property_read_u32(np, "google,remote-bus", &remote_bus); | |
251 | if (err) { | |
252 | dev_err(dev, "Couldn't read remote-bus property\n"); | |
253 | return err; | |
254 | } | |
255 | bus->remote_bus = remote_bus; | |
256 | ||
257 | bus->ec = ec; | |
258 | bus->dev = dev; | |
259 | ||
260 | bus->adap.owner = THIS_MODULE; | |
261 | strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name)); | |
262 | bus->adap.algo = &ec_i2c_algorithm; | |
263 | bus->adap.algo_data = bus; | |
264 | bus->adap.dev.parent = &pdev->dev; | |
265 | bus->adap.dev.of_node = np; | |
97720706 | 266 | bus->adap.retries = I2C_MAX_RETRIES; |
9d230c9e DA |
267 | |
268 | err = i2c_add_adapter(&bus->adap); | |
269 | if (err) { | |
270 | dev_err(dev, "cannot register i2c adapter\n"); | |
271 | return err; | |
272 | } | |
273 | platform_set_drvdata(pdev, bus); | |
274 | ||
275 | return err; | |
276 | } | |
277 | ||
278 | static int ec_i2c_remove(struct platform_device *dev) | |
279 | { | |
280 | struct ec_i2c_device *bus = platform_get_drvdata(dev); | |
281 | ||
282 | i2c_del_adapter(&bus->adap); | |
283 | ||
284 | return 0; | |
285 | } | |
286 | ||
6c97c9c1 SS |
287 | #ifdef CONFIG_OF |
288 | static const struct of_device_id cros_ec_i2c_of_match[] = { | |
289 | { .compatible = "google,cros-ec-i2c-tunnel" }, | |
290 | {}, | |
291 | }; | |
292 | MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match); | |
293 | #endif | |
294 | ||
9d230c9e DA |
295 | static struct platform_driver ec_i2c_tunnel_driver = { |
296 | .probe = ec_i2c_probe, | |
297 | .remove = ec_i2c_remove, | |
298 | .driver = { | |
299 | .name = "cros-ec-i2c-tunnel", | |
6c97c9c1 | 300 | .of_match_table = of_match_ptr(cros_ec_i2c_of_match), |
9d230c9e DA |
301 | }, |
302 | }; | |
303 | ||
304 | module_platform_driver(ec_i2c_tunnel_driver); | |
305 | ||
306 | MODULE_LICENSE("GPL"); | |
307 | MODULE_DESCRIPTION("EC I2C tunnel driver"); | |
308 | MODULE_ALIAS("platform:cros-ec-i2c-tunnel"); |