xref: /rk3399_rockchip-uboot/drivers/misc/cros_ec_i2c.c (revision 78764a4e11dd40005ba2b36848de407070ccc1a7)
1*78764a4eSHung-ying Tyan /*
2*78764a4eSHung-ying Tyan  * Chromium OS cros_ec driver - I2C interface
3*78764a4eSHung-ying Tyan  *
4*78764a4eSHung-ying Tyan  * Copyright (c) 2012 The Chromium OS Authors.
5*78764a4eSHung-ying Tyan  * See file CREDITS for list of people who contributed to this
6*78764a4eSHung-ying Tyan  * project.
7*78764a4eSHung-ying Tyan  *
8*78764a4eSHung-ying Tyan  * This program is free software; you can redistribute it and/or
9*78764a4eSHung-ying Tyan  * modify it under the terms of the GNU General Public License as
10*78764a4eSHung-ying Tyan  * published by the Free Software Foundation; either version 2 of
11*78764a4eSHung-ying Tyan  * the License, or (at your option) any later version.
12*78764a4eSHung-ying Tyan  *
13*78764a4eSHung-ying Tyan  * This program is distributed in the hope that it will be useful,
14*78764a4eSHung-ying Tyan  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*78764a4eSHung-ying Tyan  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*78764a4eSHung-ying Tyan  * GNU General Public License for more details.
17*78764a4eSHung-ying Tyan  *
18*78764a4eSHung-ying Tyan  * You should have received a copy of the GNU General Public License
19*78764a4eSHung-ying Tyan  * along with this program; if not, write to the Free Software
20*78764a4eSHung-ying Tyan  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21*78764a4eSHung-ying Tyan  * MA 02111-1307 USA
22*78764a4eSHung-ying Tyan  */
23*78764a4eSHung-ying Tyan 
24*78764a4eSHung-ying Tyan /*
25*78764a4eSHung-ying Tyan  * The Matrix Keyboard Protocol driver handles talking to the keyboard
26*78764a4eSHung-ying Tyan  * controller chip. Mostly this is for keyboard functions, but some other
27*78764a4eSHung-ying Tyan  * things have slipped in, so we provide generic services to talk to the
28*78764a4eSHung-ying Tyan  * KBC.
29*78764a4eSHung-ying Tyan  */
30*78764a4eSHung-ying Tyan 
31*78764a4eSHung-ying Tyan #include <common.h>
32*78764a4eSHung-ying Tyan #include <i2c.h>
33*78764a4eSHung-ying Tyan #include <cros_ec.h>
34*78764a4eSHung-ying Tyan 
35*78764a4eSHung-ying Tyan #ifdef DEBUG_TRACE
36*78764a4eSHung-ying Tyan #define debug_trace(fmt, b...)	debug(fmt, #b)
37*78764a4eSHung-ying Tyan #else
38*78764a4eSHung-ying Tyan #define debug_trace(fmt, b...)
39*78764a4eSHung-ying Tyan #endif
40*78764a4eSHung-ying Tyan 
41*78764a4eSHung-ying Tyan int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
42*78764a4eSHung-ying Tyan 		     const uint8_t *dout, int dout_len,
43*78764a4eSHung-ying Tyan 		     uint8_t **dinp, int din_len)
44*78764a4eSHung-ying Tyan {
45*78764a4eSHung-ying Tyan 	int old_bus = 0;
46*78764a4eSHung-ying Tyan 	/* version8, cmd8, arglen8, out8[dout_len], csum8 */
47*78764a4eSHung-ying Tyan 	int out_bytes = dout_len + 4;
48*78764a4eSHung-ying Tyan 	/* response8, arglen8, in8[din_len], checksum8 */
49*78764a4eSHung-ying Tyan 	int in_bytes = din_len + 3;
50*78764a4eSHung-ying Tyan 	uint8_t *ptr;
51*78764a4eSHung-ying Tyan 	/* Receive input data, so that args will be dword aligned */
52*78764a4eSHung-ying Tyan 	uint8_t *in_ptr;
53*78764a4eSHung-ying Tyan 	int ret;
54*78764a4eSHung-ying Tyan 
55*78764a4eSHung-ying Tyan 	old_bus = i2c_get_bus_num();
56*78764a4eSHung-ying Tyan 
57*78764a4eSHung-ying Tyan 	/*
58*78764a4eSHung-ying Tyan 	 * Sanity-check I/O sizes given transaction overhead in internal
59*78764a4eSHung-ying Tyan 	 * buffers.
60*78764a4eSHung-ying Tyan 	 */
61*78764a4eSHung-ying Tyan 	if (out_bytes > sizeof(dev->dout)) {
62*78764a4eSHung-ying Tyan 		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
63*78764a4eSHung-ying Tyan 		return -1;
64*78764a4eSHung-ying Tyan 	}
65*78764a4eSHung-ying Tyan 	if (in_bytes > sizeof(dev->din)) {
66*78764a4eSHung-ying Tyan 		debug("%s: Cannot receive %d bytes\n", __func__, din_len);
67*78764a4eSHung-ying Tyan 		return -1;
68*78764a4eSHung-ying Tyan 	}
69*78764a4eSHung-ying Tyan 	assert(dout_len >= 0);
70*78764a4eSHung-ying Tyan 	assert(dinp);
71*78764a4eSHung-ying Tyan 
72*78764a4eSHung-ying Tyan 	/*
73*78764a4eSHung-ying Tyan 	 * Copy command and data into output buffer so we can do a single I2C
74*78764a4eSHung-ying Tyan 	 * burst transaction.
75*78764a4eSHung-ying Tyan 	 */
76*78764a4eSHung-ying Tyan 	ptr = dev->dout;
77*78764a4eSHung-ying Tyan 
78*78764a4eSHung-ying Tyan 	/*
79*78764a4eSHung-ying Tyan 	 * in_ptr starts of pointing to a dword-aligned input data buffer.
80*78764a4eSHung-ying Tyan 	 * We decrement it back by the number of header bytes we expect to
81*78764a4eSHung-ying Tyan 	 * receive, so that the first parameter of the resulting input data
82*78764a4eSHung-ying Tyan 	 * will be dword aligned.
83*78764a4eSHung-ying Tyan 	 */
84*78764a4eSHung-ying Tyan 	in_ptr = dev->din + sizeof(int64_t);
85*78764a4eSHung-ying Tyan 	if (!dev->cmd_version_is_supported) {
86*78764a4eSHung-ying Tyan 		/* Send an old-style command */
87*78764a4eSHung-ying Tyan 		*ptr++ = cmd;
88*78764a4eSHung-ying Tyan 		out_bytes = dout_len + 1;
89*78764a4eSHung-ying Tyan 		in_bytes = din_len + 2;
90*78764a4eSHung-ying Tyan 		in_ptr--;	/* Expect just a status byte */
91*78764a4eSHung-ying Tyan 	} else {
92*78764a4eSHung-ying Tyan 		*ptr++ = EC_CMD_VERSION0 + cmd_version;
93*78764a4eSHung-ying Tyan 		*ptr++ = cmd;
94*78764a4eSHung-ying Tyan 		*ptr++ = dout_len;
95*78764a4eSHung-ying Tyan 		in_ptr -= 2;	/* Expect status, length bytes */
96*78764a4eSHung-ying Tyan 	}
97*78764a4eSHung-ying Tyan 	memcpy(ptr, dout, dout_len);
98*78764a4eSHung-ying Tyan 	ptr += dout_len;
99*78764a4eSHung-ying Tyan 
100*78764a4eSHung-ying Tyan 	if (dev->cmd_version_is_supported)
101*78764a4eSHung-ying Tyan 		*ptr++ = (uint8_t)
102*78764a4eSHung-ying Tyan 			 cros_ec_calc_checksum(dev->dout, dout_len + 3);
103*78764a4eSHung-ying Tyan 
104*78764a4eSHung-ying Tyan 	/* Set to the proper i2c bus */
105*78764a4eSHung-ying Tyan 	if (i2c_set_bus_num(dev->bus_num)) {
106*78764a4eSHung-ying Tyan 		debug("%s: Cannot change to I2C bus %d\n", __func__,
107*78764a4eSHung-ying Tyan 			dev->bus_num);
108*78764a4eSHung-ying Tyan 		return -1;
109*78764a4eSHung-ying Tyan 	}
110*78764a4eSHung-ying Tyan 
111*78764a4eSHung-ying Tyan 	/* Send output data */
112*78764a4eSHung-ying Tyan 	cros_ec_dump_data("out", -1, dev->dout, out_bytes);
113*78764a4eSHung-ying Tyan 	ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
114*78764a4eSHung-ying Tyan 	if (ret) {
115*78764a4eSHung-ying Tyan 		debug("%s: Cannot complete I2C write to 0x%x\n",
116*78764a4eSHung-ying Tyan 			__func__, dev->addr);
117*78764a4eSHung-ying Tyan 		ret = -1;
118*78764a4eSHung-ying Tyan 	}
119*78764a4eSHung-ying Tyan 
120*78764a4eSHung-ying Tyan 	if (!ret) {
121*78764a4eSHung-ying Tyan 		ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
122*78764a4eSHung-ying Tyan 		if (ret) {
123*78764a4eSHung-ying Tyan 			debug("%s: Cannot complete I2C read from 0x%x\n",
124*78764a4eSHung-ying Tyan 				__func__, dev->addr);
125*78764a4eSHung-ying Tyan 			ret = -1;
126*78764a4eSHung-ying Tyan 		}
127*78764a4eSHung-ying Tyan 	}
128*78764a4eSHung-ying Tyan 
129*78764a4eSHung-ying Tyan 	/* Return to original bus number */
130*78764a4eSHung-ying Tyan 	i2c_set_bus_num(old_bus);
131*78764a4eSHung-ying Tyan 	if (ret)
132*78764a4eSHung-ying Tyan 		return ret;
133*78764a4eSHung-ying Tyan 
134*78764a4eSHung-ying Tyan 	if (*in_ptr != EC_RES_SUCCESS) {
135*78764a4eSHung-ying Tyan 		debug("%s: Received bad result code %d\n", __func__, *in_ptr);
136*78764a4eSHung-ying Tyan 		return -(int)*in_ptr;
137*78764a4eSHung-ying Tyan 	}
138*78764a4eSHung-ying Tyan 
139*78764a4eSHung-ying Tyan 	if (dev->cmd_version_is_supported) {
140*78764a4eSHung-ying Tyan 		int len, csum;
141*78764a4eSHung-ying Tyan 
142*78764a4eSHung-ying Tyan 		len = in_ptr[1];
143*78764a4eSHung-ying Tyan 		if (len + 3 > sizeof(dev->din)) {
144*78764a4eSHung-ying Tyan 			debug("%s: Received length %#02x too large\n",
145*78764a4eSHung-ying Tyan 			      __func__, len);
146*78764a4eSHung-ying Tyan 			return -1;
147*78764a4eSHung-ying Tyan 		}
148*78764a4eSHung-ying Tyan 		csum = cros_ec_calc_checksum(in_ptr, 2 + len);
149*78764a4eSHung-ying Tyan 		if (csum != in_ptr[2 + len]) {
150*78764a4eSHung-ying Tyan 			debug("%s: Invalid checksum rx %#02x, calced %#02x\n",
151*78764a4eSHung-ying Tyan 			      __func__, in_ptr[2 + din_len], csum);
152*78764a4eSHung-ying Tyan 			return -1;
153*78764a4eSHung-ying Tyan 		}
154*78764a4eSHung-ying Tyan 		din_len = min(din_len, len);
155*78764a4eSHung-ying Tyan 		cros_ec_dump_data("in", -1, in_ptr, din_len + 3);
156*78764a4eSHung-ying Tyan 	} else {
157*78764a4eSHung-ying Tyan 		cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes);
158*78764a4eSHung-ying Tyan 	}
159*78764a4eSHung-ying Tyan 
160*78764a4eSHung-ying Tyan 	/* Return pointer to dword-aligned input data, if any */
161*78764a4eSHung-ying Tyan 	*dinp = dev->din + sizeof(int64_t);
162*78764a4eSHung-ying Tyan 
163*78764a4eSHung-ying Tyan 	return din_len;
164*78764a4eSHung-ying Tyan }
165*78764a4eSHung-ying Tyan 
166*78764a4eSHung-ying Tyan int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
167*78764a4eSHung-ying Tyan {
168*78764a4eSHung-ying Tyan 	/* Decode interface-specific FDT params */
169*78764a4eSHung-ying Tyan 	dev->max_frequency = fdtdec_get_int(blob, dev->node,
170*78764a4eSHung-ying Tyan 					    "i2c-max-frequency", 100000);
171*78764a4eSHung-ying Tyan 	dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
172*78764a4eSHung-ying Tyan 	if (dev->bus_num == -1) {
173*78764a4eSHung-ying Tyan 		debug("%s: Failed to read bus number\n", __func__);
174*78764a4eSHung-ying Tyan 		return -1;
175*78764a4eSHung-ying Tyan 	}
176*78764a4eSHung-ying Tyan 	dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
177*78764a4eSHung-ying Tyan 	if (dev->addr == -1) {
178*78764a4eSHung-ying Tyan 		debug("%s: Failed to read device address\n", __func__);
179*78764a4eSHung-ying Tyan 		return -1;
180*78764a4eSHung-ying Tyan 	}
181*78764a4eSHung-ying Tyan 
182*78764a4eSHung-ying Tyan 	return 0;
183*78764a4eSHung-ying Tyan }
184*78764a4eSHung-ying Tyan 
185*78764a4eSHung-ying Tyan /**
186*78764a4eSHung-ying Tyan  * Initialize I2C protocol.
187*78764a4eSHung-ying Tyan  *
188*78764a4eSHung-ying Tyan  * @param dev		CROS_EC device
189*78764a4eSHung-ying Tyan  * @param blob		Device tree blob
190*78764a4eSHung-ying Tyan  * @return 0 if ok, -1 on error
191*78764a4eSHung-ying Tyan  */
192*78764a4eSHung-ying Tyan int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
193*78764a4eSHung-ying Tyan {
194*78764a4eSHung-ying Tyan 	i2c_init(dev->max_frequency, dev->addr);
195*78764a4eSHung-ying Tyan 
196*78764a4eSHung-ying Tyan 	dev->cmd_version_is_supported = 0;
197*78764a4eSHung-ying Tyan 
198*78764a4eSHung-ying Tyan 	return 0;
199*78764a4eSHung-ying Tyan }
200