cros_ec.c revision d1fd345e2087f0362c92bd3b0a1cea7fe636ac3a
14ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass/* 24ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * ChromeOS EC multi-function device 34ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * 44ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * Copyright (C) 2012 Google, Inc 54ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * 64ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * This software is licensed under the terms of the GNU General Public 74ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * License version 2, as published by the Free Software Foundation, and 84ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * may be copied, distributed, and modified under those terms. 94ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * 104ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * This program is distributed in the hope that it will be useful, 114ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 124ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 134ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * GNU General Public License for more details. 144ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * 154ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * The ChromeOS EC multi function device is used to mux all the requests 164ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * to the EC device for its multiple features: keyboard controller, 174ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass * battery charging and regulator control, firmware update. 184ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass */ 194ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 204ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#include <linux/interrupt.h> 214ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#include <linux/slab.h> 225ebeaff5c5be9f21680b91aac77ee155d935f888Samuel Ortiz#include <linux/module.h> 234ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#include <linux/mfd/core.h> 244ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#include <linux/mfd/cros_ec.h> 254ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#include <linux/mfd/cros_ec_commands.h> 264ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 274ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glassint cros_ec_prepare_tx(struct cros_ec_device *ec_dev, 285d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson struct cros_ec_command *msg) 294ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass{ 304ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass uint8_t *out; 314ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass int csum, i; 324ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 335d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE); 344ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass out = ec_dev->dout; 354ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass out[0] = EC_CMD_VERSION0 + msg->version; 365d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson out[1] = msg->command; 375d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson out[2] = msg->outsize; 384ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass csum = out[0] + out[1] + out[2]; 395d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson for (i = 0; i < msg->outsize; i++) 405d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->outdata[i]; 415d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff); 424ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 435d4773e27e8ab37491767a6ef99ffd7100fe6341Bill Richardson return EC_MSG_TX_PROTO_BYTES + msg->outsize; 444ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass} 455ebeaff5c5be9f21680b91aac77ee155d935f888Samuel OrtizEXPORT_SYMBOL(cros_ec_prepare_tx); 464ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 476db07b6336589ff480528173e41f8f6af3f0097fBill Richardsonint cros_ec_check_result(struct cros_ec_device *ec_dev, 486db07b6336589ff480528173e41f8f6af3f0097fBill Richardson struct cros_ec_command *msg) 496db07b6336589ff480528173e41f8f6af3f0097fBill Richardson{ 506db07b6336589ff480528173e41f8f6af3f0097fBill Richardson switch (msg->result) { 516db07b6336589ff480528173e41f8f6af3f0097fBill Richardson case EC_RES_SUCCESS: 526db07b6336589ff480528173e41f8f6af3f0097fBill Richardson return 0; 536db07b6336589ff480528173e41f8f6af3f0097fBill Richardson case EC_RES_IN_PROGRESS: 546db07b6336589ff480528173e41f8f6af3f0097fBill Richardson dev_dbg(ec_dev->dev, "command 0x%02x in progress\n", 556db07b6336589ff480528173e41f8f6af3f0097fBill Richardson msg->command); 566db07b6336589ff480528173e41f8f6af3f0097fBill Richardson return -EAGAIN; 576db07b6336589ff480528173e41f8f6af3f0097fBill Richardson default: 586db07b6336589ff480528173e41f8f6af3f0097fBill Richardson dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n", 596db07b6336589ff480528173e41f8f6af3f0097fBill Richardson msg->command, msg->result); 606db07b6336589ff480528173e41f8f6af3f0097fBill Richardson return 0; 616db07b6336589ff480528173e41f8f6af3f0097fBill Richardson } 626db07b6336589ff480528173e41f8f6af3f0097fBill Richardson} 636db07b6336589ff480528173e41f8f6af3f0097fBill RichardsonEXPORT_SYMBOL(cros_ec_check_result); 646db07b6336589ff480528173e41f8f6af3f0097fBill Richardson 655ac98553afe41ffb5513fa8aac6df699a70231a3Geert Uytterhoevenstatic const struct mfd_cell cros_devs[] = { 664ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass { 674ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass .name = "cros-ec-keyb", 684ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass .id = 1, 694ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass .of_compatible = "google,cros-ec-keyb", 704ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass }, 719d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796Doug Anderson { 729d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796Doug Anderson .name = "cros-ec-i2c-tunnel", 739d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796Doug Anderson .id = 2, 749d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796Doug Anderson .of_compatible = "google,cros-ec-i2c-tunnel", 759d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796Doug Anderson }, 764ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass}; 774ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 784ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glassint cros_ec_register(struct cros_ec_device *ec_dev) 794ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass{ 804ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass struct device *dev = ec_dev->dev; 814ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass int err = 0; 824ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 834ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass if (ec_dev->din_size) { 8422f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); 8522f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones if (!ec_dev->din) 8622f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones return -ENOMEM; 874ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass } 884ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass if (ec_dev->dout_size) { 8922f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); 9022f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones if (!ec_dev->dout) 9122f9ee756bfd9ce9b066e2f90cf9f002aa7d1d44Lee Jones return -ENOMEM; 924ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass } 934ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 944ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass err = mfd_add_devices(dev, 0, cros_devs, 954ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass ARRAY_SIZE(cros_devs), 964ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass NULL, ec_dev->irq, NULL); 974ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass if (err) { 984ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass dev_err(dev, "failed to add mfd devices\n"); 99d1fd345e2087f0362c92bd3b0a1cea7fe636ac3aAndrew Bresticker return err; 1004ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass } 1014ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 102533cec8f34778de10412dfabac991cf458ebf3c9Bill Richardson dev_info(dev, "Chrome EC device registered\n"); 1034ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1044ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass return 0; 1054ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass} 1065ebeaff5c5be9f21680b91aac77ee155d935f888Samuel OrtizEXPORT_SYMBOL(cros_ec_register); 1074ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1084ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glassint cros_ec_remove(struct cros_ec_device *ec_dev) 1094ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass{ 1104ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass mfd_remove_devices(ec_dev->dev); 1114ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1124ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass return 0; 1134ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass} 1145ebeaff5c5be9f21680b91aac77ee155d935f888Samuel OrtizEXPORT_SYMBOL(cros_ec_remove); 1154ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1164ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#ifdef CONFIG_PM_SLEEP 1174ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glassint cros_ec_suspend(struct cros_ec_device *ec_dev) 1184ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass{ 1194ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass struct device *dev = ec_dev->dev; 1204ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1214ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass if (device_may_wakeup(dev)) 1224ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); 1234ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1244ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass disable_irq(ec_dev->irq); 1254ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass ec_dev->was_wake_device = ec_dev->wake_enabled; 1264ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1274ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass return 0; 1284ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass} 1295ebeaff5c5be9f21680b91aac77ee155d935f888Samuel OrtizEXPORT_SYMBOL(cros_ec_suspend); 1304ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1314ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glassint cros_ec_resume(struct cros_ec_device *ec_dev) 1324ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass{ 1334ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass enable_irq(ec_dev->irq); 1344ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1354ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass if (ec_dev->wake_enabled) { 1364ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass disable_irq_wake(ec_dev->irq); 1374ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass ec_dev->wake_enabled = 0; 1384ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass } 1394ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass 1404ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass return 0; 1414ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass} 1425ebeaff5c5be9f21680b91aac77ee155d935f888Samuel OrtizEXPORT_SYMBOL(cros_ec_resume); 1435ebeaff5c5be9f21680b91aac77ee155d935f888Samuel Ortiz 1444ab6174e8cdb007cf500e484bdf454b8d14d524aSimon Glass#endif 145a865a589144da6dbf26750b7193a9748da159305Bill Richardson 146a865a589144da6dbf26750b7193a9748da159305Bill RichardsonMODULE_LICENSE("GPL"); 147a865a589144da6dbf26750b7193a9748da159305Bill RichardsonMODULE_DESCRIPTION("ChromeOS EC core driver"); 148