xref: /aosp_15_r20/external/coreboot/src/include/device/i2c_simple.h (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #ifndef _DEVICE_I2C_SIMPLE_H_
4 #define _DEVICE_I2C_SIMPLE_H_
5 
6 #include <commonlib/helpers.h>
7 #include <device/i2c.h>
8 #include <stdint.h>
9 
10 int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
11 			  int count);
12 
13 #define SOFTWARE_I2C_MAX_BUS 10		/* increase as necessary */
14 
15 struct software_i2c_ops {
16 	void (*set_sda)(unsigned int bus, int high);
17 	void (*set_scl)(unsigned int bus, int high);
18 	int (*get_sda)(unsigned int bus);
19 	int (*get_scl)(unsigned int bus);
20 };
21 
22 extern struct software_i2c_ops *software_i2c[];
23 
24 int software_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
25 			  int count);
26 void software_i2c_wedge_ack(unsigned int bus, u8 slave);
27 void software_i2c_wedge_read(unsigned int bus, u8 slave, u8 reg, int bit_count);
28 void software_i2c_wedge_write(unsigned int bus, u8 slave, u8 reg,
29 			      int bit_count);
30 
31 int i2c_read_field(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t *data,
32 		   uint8_t mask, uint8_t shift);
33 int i2c_write_field(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t data,
34 		    uint8_t mask, uint8_t shift);
35 
36 /*
37  * software_i2c is supposed to be a debug feature. It's usually not compiled in,
38  * but when it is it can be dynamically enabled at runtime for certain buses.
39  * Need this ugly stub to arbitrate since I2C device drivers hardcode
40  * 'i2c_transfer()' as their entry point.
41  */
i2c_transfer(unsigned int bus,struct i2c_msg * segments,int count)42 static inline int i2c_transfer(unsigned int bus, struct i2c_msg *segments,
43 			       int count)
44 {
45 	if (CONFIG(SOFTWARE_I2C))
46 		if (bus < SOFTWARE_I2C_MAX_BUS && software_i2c[bus])
47 			return software_i2c_transfer(bus, segments, count);
48 
49 	return platform_i2c_transfer(bus, segments, count);
50 }
51 
52 /*
53  * Read a raw chunk of data in one segment and one frame.
54  *
55  * [start][slave addr][r][data][stop]
56  */
i2c_read_raw(unsigned int bus,uint8_t slave,uint8_t * data,int len)57 static inline int i2c_read_raw(unsigned int bus, uint8_t slave, uint8_t *data,
58 			       int len)
59 {
60 	struct i2c_msg seg = {
61 		.flags = I2C_M_RD, .slave = slave, .buf = data, .len = len
62 	};
63 
64 	return i2c_transfer(bus, &seg, 1);
65 }
66 
67 /*
68  * Write a raw chunk of data in one segment and one frame.
69  *
70  * [start][slave addr][w][data][stop]
71  */
i2c_write_raw(unsigned int bus,uint8_t slave,uint8_t * data,int len)72 static inline int i2c_write_raw(unsigned int bus, uint8_t slave, uint8_t *data,
73 				int len)
74 {
75 	struct i2c_msg seg = {
76 		.flags = 0, .slave = slave, .buf = data, .len = len
77 	};
78 
79 	return i2c_transfer(bus, &seg, 1);
80 }
81 
82 /**
83  * Read multi-bytes with two segments in one frame
84  *
85  * [start][slave addr][w][register addr][start][slave addr][r][data...][stop]
86  */
i2c_read_bytes(unsigned int bus,uint8_t slave,uint8_t reg,uint8_t * data,int len)87 static inline int i2c_read_bytes(unsigned int bus, uint8_t slave, uint8_t reg,
88 				 uint8_t *data, int len)
89 {
90 	struct i2c_msg seg[2];
91 
92 	seg[0].flags = 0;
93 	seg[0].slave = slave;
94 	seg[0].buf   = &reg;
95 	seg[0].len   = 1;
96 	seg[1].flags = I2C_M_RD;
97 	seg[1].slave = slave;
98 	seg[1].buf   = data;
99 	seg[1].len   = len;
100 
101 	return i2c_transfer(bus, seg, ARRAY_SIZE(seg));
102 }
103 
104 /**
105  * Read a byte with two segments in one frame
106  *
107  * [start][slave addr][w][register addr][start][slave addr][r][data][stop]
108  */
i2c_readb(unsigned int bus,uint8_t slave,uint8_t reg,uint8_t * data)109 static inline int i2c_readb(unsigned int bus, uint8_t slave, uint8_t reg,
110 			    uint8_t *data)
111 {
112 	struct i2c_msg seg[2];
113 
114 	seg[0].flags = 0;
115 	seg[0].slave = slave;
116 	seg[0].buf   = &reg;
117 	seg[0].len   = 1;
118 	seg[1].flags = I2C_M_RD;
119 	seg[1].slave = slave;
120 	seg[1].buf   = data;
121 	seg[1].len   = 1;
122 
123 	return i2c_transfer(bus, seg, ARRAY_SIZE(seg));
124 }
125 
126 /**
127  * Write a byte with one segment in one frame.
128  *
129  * [start][slave addr][w][register addr][data][stop]
130  */
i2c_writeb(unsigned int bus,uint8_t slave,uint8_t reg,uint8_t data)131 static inline int i2c_writeb(unsigned int bus, uint8_t slave, uint8_t reg,
132 			     uint8_t data)
133 {
134 	struct i2c_msg seg;
135 	uint8_t buf[] = {reg, data};
136 
137 	seg.flags = 0;
138 	seg.slave = slave;
139 	seg.buf   = buf;
140 	seg.len   = ARRAY_SIZE(buf);
141 
142 	return i2c_transfer(bus, &seg, 1);
143 }
144 
145 /**
146  * Read multi-bytes from an I2C device with two bytes register address/offset
147  * with two segments in one frame
148  *
149  * [start][slave addr][w][register high addr][register low addr]
150  * [start][slave addr][r][data...][stop]
151  */
i2c_2ba_read_bytes(unsigned int bus,uint8_t slave,uint16_t offset,uint8_t * data,int len)152 static inline int i2c_2ba_read_bytes(unsigned int bus, uint8_t slave, uint16_t offset,
153 				     uint8_t *data, int len)
154 {
155 	struct i2c_msg seg[2];
156 	uint8_t eeprom_offset[2];
157 
158 	eeprom_offset[0] = offset >> 8;
159 	eeprom_offset[1] = offset & 0xff;
160 
161 	seg[0].flags = 0;
162 	seg[0].slave = slave;
163 	seg[0].buf   = eeprom_offset;
164 	seg[0].len   = sizeof(eeprom_offset);
165 	seg[1].flags = I2C_M_RD;
166 	seg[1].slave = slave;
167 	seg[1].buf   = data;
168 	seg[1].len   = len;
169 
170 	return i2c_transfer(bus, seg, ARRAY_SIZE(seg));
171 }
172 
173 #endif	/* _DEVICE_I2C_SIMPLE_H_ */
174