1 /*
2 * Copyright (c) 2019 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT litex_i2c
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(i2c_litex, CONFIG_I2C_LOG_LEVEL);
14
15 #include "i2c-priv.h"
16 #include "i2c_bitbang.h"
17
18 #include <soc.h>
19
20 #define SCL_BIT_POS 0
21 #define SDA_DIR_BIT_POS 1
22 #define SDA_BIT_W_POS 2
23 #define SDA_BIT_R_POS 0
24
25 #define SDA_DIR_OUTPUT 1
26 #define SDA_DIR_INPUT 0
27
28 #define HIGH_STATE_ON_I2C_LINES 0x7
29
30 struct i2c_litex_cfg {
31 uint32_t write_addr;
32 uint32_t read_addr;
33 uint32_t bitrate;
34 };
35
36 #define GET_I2C_CFG(dev) \
37 ((const struct i2c_litex_cfg *) dev->config)
38
39 #define GET_I2C_BITBANG(dev) \
40 ((struct i2c_bitbang *) dev->data)
41
set_bit(uint32_t addr,uint32_t bit,uint32_t val)42 static inline void set_bit(uint32_t addr, uint32_t bit, uint32_t val)
43 {
44 uint32_t mask = BIT(bit);
45
46 if (val) {
47 litex_write8(litex_read8(addr) | mask, addr);
48 } else {
49 litex_write8(litex_read8(addr) & ~mask, addr);
50 }
51 }
52
get_bit(uint32_t addr,uint32_t bit)53 static inline int get_bit(uint32_t addr, uint32_t bit)
54 {
55 uint32_t mask = BIT(bit);
56
57 return !!(litex_read8(addr) & mask);
58 }
59
i2c_litex_bitbang_set_scl(void * context,int state)60 static void i2c_litex_bitbang_set_scl(void *context, int state)
61 {
62 const struct i2c_litex_cfg *config =
63 (const struct i2c_litex_cfg *) context;
64
65 set_bit(config->write_addr, SCL_BIT_POS, state);
66 }
67
i2c_litex_bitbang_set_sda(void * context,int state)68 static void i2c_litex_bitbang_set_sda(void *context, int state)
69 {
70 const struct i2c_litex_cfg *config =
71 (const struct i2c_litex_cfg *) context;
72
73 set_bit(config->write_addr, SDA_DIR_BIT_POS, SDA_DIR_OUTPUT);
74 set_bit(config->write_addr, SDA_BIT_W_POS, state);
75 }
76
i2c_litex_bitbang_get_sda(void * context)77 static int i2c_litex_bitbang_get_sda(void *context)
78 {
79 const struct i2c_litex_cfg *config =
80 (const struct i2c_litex_cfg *) context;
81
82 set_bit(config->write_addr, SDA_DIR_BIT_POS, SDA_DIR_INPUT);
83 return get_bit(config->read_addr, SDA_BIT_R_POS);
84 }
85
86 static const struct i2c_bitbang_io i2c_litex_bitbang_io = {
87 .set_scl = i2c_litex_bitbang_set_scl,
88 .set_sda = i2c_litex_bitbang_set_sda,
89 .get_sda = i2c_litex_bitbang_get_sda,
90 };
91
i2c_litex_init(const struct device * dev)92 static int i2c_litex_init(const struct device *dev)
93 {
94 const struct i2c_litex_cfg *config = GET_I2C_CFG(dev);
95 struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
96 int ret;
97
98 litex_write8(litex_read8(config->write_addr) | HIGH_STATE_ON_I2C_LINES, config->write_addr);
99 i2c_bitbang_init(bitbang, &i2c_litex_bitbang_io, (void *)config);
100
101 ret = i2c_bitbang_configure(bitbang,
102 I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
103 if (ret != 0) {
104 LOG_ERR("failed to configure I2C bitbang: %d", ret);
105 }
106
107 return ret;
108 }
109
i2c_litex_configure(const struct device * dev,uint32_t dev_config)110 static int i2c_litex_configure(const struct device *dev, uint32_t dev_config)
111 {
112 struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
113
114 return i2c_bitbang_configure(bitbang, dev_config);
115 }
116
i2c_litex_get_config(const struct device * dev,uint32_t * config)117 static int i2c_litex_get_config(const struct device *dev, uint32_t *config)
118 {
119 struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
120
121 return i2c_bitbang_get_config(bitbang, config);
122 }
123
i2c_litex_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)124 static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs,
125 uint8_t num_msgs, uint16_t addr)
126 {
127 struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
128
129 return i2c_bitbang_transfer(bitbang, msgs, num_msgs, addr);
130 }
131
i2c_litex_recover_bus(const struct device * dev)132 static int i2c_litex_recover_bus(const struct device *dev)
133 {
134 struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
135
136 return i2c_bitbang_recover_bus(bitbang);
137 }
138
139 static DEVICE_API(i2c, i2c_litex_driver_api) = {
140 .configure = i2c_litex_configure,
141 .get_config = i2c_litex_get_config,
142 .transfer = i2c_litex_transfer,
143 .recover_bus = i2c_litex_recover_bus,
144 #ifdef CONFIG_I2C_RTIO
145 .iodev_submit = i2c_iodev_submit_fallback,
146 #endif
147 };
148
149 /* Device Instantiation */
150
151 #define I2C_LITEX_INIT(n) \
152 static const struct i2c_litex_cfg i2c_litex_cfg_##n = { \
153 .write_addr = DT_INST_REG_ADDR_BY_NAME(n, write), \
154 .read_addr = DT_INST_REG_ADDR_BY_NAME(n, read), \
155 .bitrate = DT_INST_PROP(n, clock_frequency), \
156 }; \
157 \
158 static struct i2c_bitbang i2c_bitbang_##n; \
159 \
160 I2C_DEVICE_DT_INST_DEFINE(n, \
161 i2c_litex_init, \
162 NULL, \
163 &i2c_bitbang_##n, \
164 &i2c_litex_cfg_##n, \
165 POST_KERNEL, \
166 CONFIG_I2C_INIT_PRIORITY, \
167 &i2c_litex_driver_api \
168 );
169
170 DT_INST_FOREACH_STATUS_OKAY(I2C_LITEX_INIT)
171