CHROMIUM: mfd: chromeos_ec: suspend/resume fixes
[cascardo/linux.git] / drivers / mfd / chromeos_ec.c
1 /*
2  *  Copyright (C) 2012 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  *  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.
13  *
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
17  *
18  *
19  * The ChromeOS EC multi function device is used to mux all the requests
20  * to the EC device for its multiple features : keyboard controller,
21  * battery charging and regulator control, firmware update.
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/i2c.h>
27 #include <linux/interrupt.h>
28 #include <linux/mfd/core.h>
29 #include <linux/mfd/chromeos_ec.h>
30 #include <linux/mfd/chromeos_ec_commands.h>
31 #include <linux/platform_device.h>
32 #include <linux/slab.h>
33
34
35 #define COMMAND_MAX_TRIES 3
36
37 static inline struct chromeos_ec_device *to_ec_dev(struct device *dev)
38 {
39         struct i2c_client *client = to_i2c_client(dev);
40         return i2c_get_clientdata(client);
41 }
42
43 static int cros_ec_command_xfer_noretry(struct chromeos_ec_device *ec_dev,
44                                         struct chromeos_ec_msg *msg)
45 {
46         int ret;
47         int i;
48         int packet_len;
49         u8 res_code;
50         u8 *out_buf = NULL;
51         u8 *in_buf = NULL;
52         u8 sum;
53         struct i2c_msg i2c_msg[2];
54
55         i2c_msg[0].addr = ec_dev->client->addr;
56         i2c_msg[0].flags = 0;
57         i2c_msg[1].addr = ec_dev->client->addr;
58         i2c_msg[1].flags = I2C_M_RD;
59
60         if (msg->in_len) {
61                 /* allocate larger packet
62                  * (one byte for checksum, one for result code)
63                  */
64                 packet_len = msg->in_len + 2;
65                 in_buf = kzalloc(packet_len, GFP_KERNEL);
66                 if (!in_buf)
67                         goto done;
68                 i2c_msg[1].len = packet_len;
69                 i2c_msg[1].buf = (char *)in_buf;
70         } else {
71                 i2c_msg[1].len = 1;
72                 i2c_msg[1].buf = (char *)&res_code;
73         }
74
75         if (msg->out_len) {
76                 /* allocate larger packet
77                  * (one byte for checksum, one for command code)
78                  */
79                 packet_len = msg->out_len + 2;
80                 out_buf = kzalloc(packet_len, GFP_KERNEL);
81                 if (!out_buf)
82                         goto done;
83                 i2c_msg[0].len = packet_len;
84                 i2c_msg[0].buf = (char *)out_buf;
85                 out_buf[0] = msg->cmd;
86
87                 /* copy message payload and compute checksum */
88                 for (i = 0, sum = 0; i < msg->out_len; i++) {
89                         out_buf[i + 1] = msg->out_buf[i];
90                         sum += out_buf[i + 1];
91                 }
92                 out_buf[msg->out_len + 1] = sum;
93         } else {
94                 i2c_msg[0].len = 1;
95                 i2c_msg[0].buf = (char *)&msg->cmd;
96         }
97
98         /* send command to EC and read answer */
99         ret = i2c_transfer(ec_dev->client->adapter, i2c_msg, 2);
100         if (ret < 0) {
101                 dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret);
102                 goto done;
103         } else if (ret != 2) {
104                 dev_err(ec_dev->dev, "failed to get response: %d\n", ret);
105                 ret = -EIO;
106                 goto done;
107         }
108
109         /* check response error code */
110         if (i2c_msg[1].buf[0]) {
111                 dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
112                          msg->cmd, i2c_msg[1].buf[0]);
113                 ret = -EINVAL;
114                 goto done;
115         }
116         if (msg->in_len) {
117                 /* copy response packet payload and compute checksum */
118                 for (i = 0, sum = 0; i < msg->in_len; i++) {
119                         msg->in_buf[i] = in_buf[i + 1];
120                         sum += in_buf[i + 1];
121                 }
122 #ifdef DEBUG
123                 dev_dbg(ec_dev->dev, "packet: ");
124                 for (i = 0; i < i2c_msg[1].len; i++)
125                         printk(" %02x", in_buf[i]);
126                 printk(", sum = %02x\n", sum);
127 #endif
128                 if (sum != in_buf[msg->in_len + 1]) {
129                         dev_err(ec_dev->dev, "bad packet checksum\n");
130                         ret = -EBADMSG;
131                         goto done;
132                 }
133         }
134
135         ret = 0;
136  done:
137         kfree(in_buf);
138         kfree(out_buf);
139         return ret;
140 }
141
142 static int cros_ec_command_xfer(struct chromeos_ec_device *ec_dev,
143                                  struct chromeos_ec_msg *msg)
144 {
145         int tries;
146         int ret;
147         /*
148          * Try the command a few times in case there are transmission errors.
149          * It is possible that this is overkill, but we don't completely trust
150          * i2c.
151          */
152         for (tries = 0; tries < COMMAND_MAX_TRIES; tries++) {
153                 ret = cros_ec_command_xfer_noretry(ec_dev, msg);
154                 if (ret >= 0)
155                         return ret;
156         }
157         dev_err(ec_dev->dev, "ec_command failed with %d (%d tries)\n",
158                 ret, tries);
159         return ret;
160 }
161
162 static int cros_ec_command_raw(struct chromeos_ec_device *ec_dev,
163                                struct i2c_msg *msgs, int num)
164 {
165         return i2c_transfer(ec_dev->client->adapter, msgs, num);
166 }
167
168 static int cros_ec_command_recv(struct chromeos_ec_device *ec_dev,
169                                 char cmd, void *buf, int buf_len)
170 {
171         struct chromeos_ec_msg msg;
172
173         msg.cmd = cmd;
174         msg.in_buf = buf;
175         msg.in_len = buf_len;
176         msg.out_buf = NULL;
177         msg.out_len = 0;
178
179         return cros_ec_command_xfer(ec_dev, &msg);
180 }
181
182 static int cros_ec_command_send(struct chromeos_ec_device *ec_dev,
183                                 char cmd, void *buf, int buf_len)
184 {
185         struct chromeos_ec_msg msg;
186
187         msg.cmd = cmd;
188         msg.out_buf = buf;
189         msg.out_len = buf_len;
190         msg.in_buf = NULL;
191         msg.in_len = 0;
192
193         return cros_ec_command_xfer(ec_dev, &msg);
194 }
195
196 static irqreturn_t ec_irq_thread(int irq, void *data)
197 {
198         struct chromeos_ec_device *ec = data;
199
200         if (device_may_wakeup(ec->dev))
201                 pm_wakeup_event(ec->dev, 0);
202
203         blocking_notifier_call_chain(&ec->event_notifier, 1, ec);
204
205         return IRQ_HANDLED;
206 }
207
208 static int __devinit check_protocol_version(struct chromeos_ec_device *ec)
209 {
210         int ret;
211         struct ec_response_proto_version data;
212
213         ret = cros_ec_command_recv(ec, EC_CMD_PROTO_VERSION,
214                                    &data, sizeof(data));
215         if (ret < 0)
216                 return ret;
217         dev_info(ec->dev, "protocol version: %d\n", data.version);
218         if (data.version != EC_PROTO_VERSION)
219                 return -EPROTONOSUPPORT;
220
221         return 0;
222 }
223
224 static struct mfd_cell cros_devs[] = {
225         {
226                 .name = "mkbp",
227                 .id = 1,
228         },
229         {
230                 .name = "cros_ec-fw",
231                 .id = 2,
232         },
233         {
234                 .name = "cros_ec-i2c",
235                 .id = 3,
236         },
237 };
238
239 static int __devinit cros_ec_probe(struct i2c_client *client,
240                                    const struct i2c_device_id *dev_id)
241 {
242         struct device *dev = &client->dev;
243         struct chromeos_ec_device *ec_dev = NULL;
244         int err;
245
246         dev_dbg(dev, "probing\n");
247
248         ec_dev = kzalloc(sizeof(*ec_dev), GFP_KERNEL);
249         if (ec_dev == NULL) {
250                 err = -ENOMEM;
251                 dev_err(dev, "cannot allocate\n");
252                 goto fail;
253         }
254
255         ec_dev->client = client;
256         ec_dev->dev = dev;
257         i2c_set_clientdata(client, ec_dev);
258         ec_dev->irq = client->irq;
259         ec_dev->command_send = cros_ec_command_send;
260         ec_dev->command_recv = cros_ec_command_recv;
261         ec_dev->command_xfer = cros_ec_command_xfer;
262         ec_dev->command_raw  = cros_ec_command_raw;
263
264         BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
265
266         err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
267                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
268                                    "chromeos-ec", ec_dev);
269         if (err) {
270                 dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
271                 goto fail;
272         }
273
274         err = check_protocol_version(ec_dev);
275         if (err < 0) {
276                 dev_err(dev, "protocol version check failed: %d\n", err);
277                 goto fail_irq;
278         }
279
280         err = mfd_add_devices(dev, 0, cros_devs,
281                               ARRAY_SIZE(cros_devs),
282                               NULL, ec_dev->irq);
283         if (err)
284                 goto fail_irq;
285
286         return 0;
287 fail_irq:
288         free_irq(ec_dev->irq, ec_dev);
289 fail:
290         kfree(ec_dev);
291         return err;
292 }
293
294 #ifdef CONFIG_PM_SLEEP
295 static int cros_ec_suspend(struct device *dev)
296 {
297         struct chromeos_ec_device *ec = to_ec_dev(dev);
298
299         if (device_may_wakeup(dev))
300                 ec->wake_enabled = !enable_irq_wake(ec->irq);
301
302         disable_irq(ec->irq);
303
304         return 0;
305 }
306
307 static int cros_ec_resume(struct device *dev)
308 {
309         struct chromeos_ec_device *ec = to_ec_dev(dev);
310
311         enable_irq(ec->irq);
312
313         if (ec->wake_enabled) {
314                 disable_irq_wake(ec->irq);
315                 ec->wake_enabled = 0;
316         }
317
318         return 0;
319 }
320 #endif
321
322 static SIMPLE_DEV_PM_OPS(cros_ec_pm_ops, cros_ec_suspend, cros_ec_resume);
323
324 static const struct i2c_device_id cros_ec_i2c_id[] = {
325         { "chromeos-ec", 0 },
326         { }
327 };
328 MODULE_DEVICE_TABLE(i2c, mkbp_i2c_id);
329
330 static struct i2c_driver cros_ec_driver = {
331         .driver = {
332                 .name   = "chromeos-ec",
333                 .owner  = THIS_MODULE,
334                 .pm     = &cros_ec_pm_ops,
335         },
336         .probe          = cros_ec_probe,
337         .id_table       = cros_ec_i2c_id,
338 };
339
340 module_i2c_driver(cros_ec_driver);
341
342 MODULE_LICENSE("GPL");
343 MODULE_DESCRIPTION("ChromeOS EC multi function device");