CHROMIUM: mfd: chromeos_ec: use threaded irq for EC
[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/platform_device.h>
31 #include <linux/slab.h>
32
33
34 #define MKBP_MAX_TRIES 3
35
36 /* Send a one-byte command to the keyboard and receive a response of length
37  * BUF_LEN.  Return BUF_LEN, or a negative error code.
38  */
39 static int mkbp_command_noretry(struct chromeos_ec_device *ec_dev,
40                                 char cmd, uint8_t *buf, int buf_len)
41 {
42         int ret;
43         int i;
44         int packet_len;
45         uint8_t *packet;
46         uint8_t sum;
47
48         /* allocate larger packet (one extra byte for checksum) */
49         packet_len = buf_len + MKBP_MSG_PROTO_BYTES;
50         packet = kzalloc(packet_len, GFP_KERNEL);
51         if (!packet)
52                 return -ENOMEM;
53
54         /* send command to EC */
55         ret = i2c_master_send(ec_dev->client, &cmd, 1);
56         if (ret < 0) {
57                 dev_err(ec_dev->dev, "i2c send failed: %d\n", ret);
58                 goto done;
59         }
60         /* receive response */
61         ret = i2c_master_recv(ec_dev->client, packet, packet_len);
62         if (ret < 0) {
63                 dev_err(ec_dev->dev, "i2c receive failed: %d\n", ret);
64                 goto done;
65         } else if (ret != packet_len) {
66                 dev_err(ec_dev->dev, "expected %d bytes, got %d\n",
67                         packet_len, ret);
68                 ret = -EIO;
69                 goto done;
70         }
71         /* copy response packet payload and compute checksum */
72         for (i = 0, sum = 0; i < buf_len; i++) {
73                 buf[i] = packet[i];
74                 sum += buf[i];
75         }
76 #ifdef DEBUG
77         dev_dbg(ec_dev->dev, "packet: ");
78         for (i = 0; i < packet_len; i++) {
79                 printk(" %02x", packet[i]);
80         }
81         printk(", sum = %02x\n", sum);
82 #endif
83         if (sum != packet[packet_len - 1]) {
84                 dev_err(ec_dev->dev, "bad keyboard packet checksum\n");
85                 ret = -EIO;
86                 goto done;
87         }
88         ret = buf_len;
89  done:
90         kfree(packet);
91         return ret;
92 }
93
94 static int mkbp_command(struct chromeos_ec_device *ec_dev,
95                         char cmd, uint8_t *buf, int buf_len)
96 {
97         int try;
98         int ret;
99         /*
100          * Try the command a few times in case there are transmission errors.
101          * It is possible that this is overkill, but we don't completely trust
102          * i2c.
103          */
104         for (try = 0; try < MKBP_MAX_TRIES; try++) {
105                 ret = mkbp_command_noretry(ec_dev, cmd, buf, buf_len);
106                 if (ret >= 0)
107                         return ret;
108         }
109         dev_err(ec_dev->dev, "mkbp_command failed with %d (%d tries)\n",
110                 ret, try);
111         return ret;
112 }
113
114 static irqreturn_t ec_irq_thread(int irq, void *data)
115 {
116         struct chromeos_ec_device *ec = data;
117
118         blocking_notifier_call_chain(&ec->event_notifier, 1, ec);
119
120         return IRQ_HANDLED;
121 }
122
123 static int __devinit mkbp_check_protocol_version(struct chromeos_ec_device *ec)
124 {
125         int ret;
126         char buf[4];
127         static char expected_version[4] = {1, 0, 0, 0};
128         int i;
129
130         ret = mkbp_command(ec, MKBP_CMDC_PROTO_VER, buf, sizeof(buf));
131         if (ret < 0)
132                 return ret;
133         for (i = 0; i < sizeof(expected_version); i++) {
134                 if (buf[i] != expected_version[i])
135                         return -EPROTONOSUPPORT;
136         }
137         return 0;
138 }
139
140 static struct mfd_cell cros_devs[] = {
141         {
142                 .name = "mkbp",
143                 .id = 1,
144         },
145 };
146
147 static int __devinit cros_ec_probe(struct i2c_client *client,
148                                    const struct i2c_device_id *dev_id)
149 {
150         struct device *dev = &client->dev;
151         struct chromeos_ec_device *ec_dev = NULL;
152         int err;
153
154         dev_dbg(dev, "probing\n");
155
156         ec_dev = kzalloc(sizeof(*ec_dev), GFP_KERNEL);
157         if (ec_dev == NULL) {
158                 err = -ENOMEM;
159                 dev_err(dev, "cannot allocate\n");
160                 goto fail;
161         }
162
163         ec_dev->client = client;
164         ec_dev->dev = dev;
165         i2c_set_clientdata(client, ec_dev);
166         ec_dev->irq = client->irq;
167         ec_dev->send_command = mkbp_command;
168
169         BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
170
171         err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
172                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
173                                    "chromeos-ec", ec_dev);
174         if (err) {
175                 dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
176                 goto fail;
177         }
178
179         err = mkbp_check_protocol_version(ec_dev);
180         if (err < 0) {
181                 dev_err(dev, "protocol version check failed: %d\n", err);
182                 goto fail_irq;
183         }
184
185         err = mfd_add_devices(dev, 0, cros_devs, ARRAY_SIZE(cros_devs),
186                               NULL, ec_dev->irq);
187         if (err)
188                 goto fail_irq;
189
190         return 0;
191 fail_irq:
192         free_irq(ec_dev->irq, ec_dev);
193 fail:
194         kfree(ec_dev);
195         return err;
196 }
197
198 #ifdef CONFIG_PM_SLEEP
199 static int cros_ec_suspend(struct device *dev)
200 {
201         return 0;
202 }
203
204 static int cros_ec_resume(struct device *dev)
205 {
206         return 0;
207 }
208 #endif
209
210 static SIMPLE_DEV_PM_OPS(cros_ec_pm_ops, cros_ec_suspend, cros_ec_resume);
211
212 static const struct i2c_device_id cros_ec_i2c_id[] = {
213         { "chromeos-ec", 0 },
214         { }
215 };
216 MODULE_DEVICE_TABLE(i2c, mkbp_i2c_id);
217
218 static struct i2c_driver cros_ec_driver = {
219         .driver = {
220                 .name   = "chromeos-ec",
221                 .owner  = THIS_MODULE,
222                 .pm     = &cros_ec_pm_ops,
223         },
224         .probe          = cros_ec_probe,
225         .id_table       = cros_ec_i2c_id,
226 };
227
228 module_i2c_driver(cros_ec_driver);
229
230 MODULE_LICENSE("GPL");
231 MODULE_DESCRIPTION("ChromeOS EC multi function device");