blob: 9f3af1130e1145987b597deee398c71028dc583c [file] [log] [blame]
Angel Pons32859fc2020-04-02 23:48:27 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Nico Huber0f2dd1e2017-08-01 14:02:40 +02002
3#ifndef _DEVICE_I2C_SIMPLE_H_
4#define _DEVICE_I2C_SIMPLE_H_
5
6#include <commonlib/helpers.h>
7#include <device/i2c.h>
Elyes HAOUAS5817c562020-07-12 09:03:22 +02008#include <stdint.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02009
10int 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
15struct 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
22extern struct software_i2c_ops *software_i2c[];
23
24int software_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
25 int count);
26void software_i2c_wedge_ack(unsigned int bus, u8 slave);
27void software_i2c_wedge_read(unsigned int bus, u8 slave, u8 reg, int bit_count);
28void software_i2c_wedge_write(unsigned int bus, u8 slave, u8 reg,
29 int bit_count);
30
31int i2c_read_field(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t *data,
32 uint8_t mask, uint8_t shift);
33int 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,
Martin Roth0949e732021-10-01 14:28:22 -060038 * but when it is it can be dynamically enabled at runtime for certain buses.
Nico Huber0f2dd1e2017-08-01 14:02:40 +020039 * Need this ugly stub to arbitrate since I2C device drivers hardcode
40 * 'i2c_transfer()' as their entry point.
41 */
42static inline int i2c_transfer(unsigned int bus, struct i2c_msg *segments,
43 int count)
44{
Julius Werner5d1f9a02019-03-07 17:07:26 -080045 if (CONFIG(SOFTWARE_I2C))
Nico Huber0f2dd1e2017-08-01 14:02:40 +020046 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 */
57static 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 */
72static 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 */
87static 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 */
109static 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 */
131static 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
Felix Held8fbf88f2022-03-08 17:48:59 +0100145/**
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 */
152static 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
Nico Huber0f2dd1e2017-08-01 14:02:40 +0200173#endif /* _DEVICE_I2C_SIMPLE_H_ */