Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller
  3 *
  4 * Copyright (C) 2016 Google, Inc
  5 *
  6 * This software is licensed under the terms of the GNU General Public
  7 * License version 2, as published by the Free Software Foundation, and
  8 * may be copied, distributed, and modified under those terms.
  9 *
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 * GNU General Public License for more details.
 14 *
 15 * This driver uses the Chrome OS EC byte-level message-based protocol for
 16 * communicating the keyboard state (which keys are pressed) from a keyboard EC
 17 * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
 18 * but everything else (including deghosting) is done here.  The main
 19 * motivation for this is to keep the EC firmware as simple as possible, since
 20 * it cannot be easily upgraded and EC flash/IRAM space is relatively
 21 * expensive.
 22 */
 23
 24#include <linux/io.h>
 25#include <linux/mfd/cros_ec.h>
 26#include <linux/mfd/cros_ec_commands.h>
 27#include <linux/mfd/cros_ec_lpc_mec.h>
 28
 29static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
 30{
 31	int i;
 32	int sum = 0;
 33
 34	for (i = 0; i < length; ++i) {
 35		dest[i] = inb(offset + i);
 36		sum += dest[i];
 37	}
 38
 39	/* Return checksum of all bytes read */
 40	return sum;
 41}
 42
 43static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
 44{
 45	int i;
 46	int sum = 0;
 47
 48	for (i = 0; i < length; ++i) {
 49		outb(msg[i], offset + i);
 50		sum += msg[i];
 51	}
 52
 53	/* Return checksum of all bytes written */
 54	return sum;
 55}
 56
 57#ifdef CONFIG_CROS_EC_LPC_MEC
 58
 59u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
 60{
 61	if (length == 0)
 62		return 0;
 63
 64	/* Access desired range through EMI interface */
 65	if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
 66		/* Ensure we don't straddle EMI region */
 67		if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
 68			return 0;
 69
 70		return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length,
 71						dest);
 72	}
 73
 74	if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
 75		    offset < MEC_EMI_RANGE_START))
 76		return 0;
 77
 78	return lpc_read_bytes(offset, length, dest);
 79}
 80
 81u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
 82{
 83	if (length == 0)
 84		return 0;
 85
 86	/* Access desired range through EMI interface */
 87	if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
 88		/* Ensure we don't straddle EMI region */
 89		if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
 90			return 0;
 91
 92		return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length,
 93						msg);
 94	}
 95
 96	if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
 97		    offset < MEC_EMI_RANGE_START))
 98		return 0;
 99
100	return lpc_write_bytes(offset, length, msg);
101}
102
103void cros_ec_lpc_reg_init(void)
104{
105	cros_ec_lpc_mec_init();
106}
107
108void cros_ec_lpc_reg_destroy(void)
109{
110	cros_ec_lpc_mec_destroy();
111}
112
113#else /* CONFIG_CROS_EC_LPC_MEC */
114
115u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
116{
117	return lpc_read_bytes(offset, length, dest);
118}
119
120u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
121{
122	return lpc_write_bytes(offset, length, msg);
123}
124
125void cros_ec_lpc_reg_init(void)
126{
127}
128
129void cros_ec_lpc_reg_destroy(void)
130{
131}
132
133#endif /* CONFIG_CROS_EC_LPC_MEC */