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 = ®
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 = ®
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