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 #include "i2c_bitbang.h"
12 
13 #define SCL_BIT_POS                0
14 #define SDA_DIR_BIT_POS            1
15 #define SDA_BIT_W_POS              2
16 #define SDA_BIT_R_POS              0
17 
18 #define SDA_DIR_OUTPUT             1
19 #define SDA_DIR_INPUT              0
20 
21 #define HIGH_STATE_ON_I2C_LINES    0x7
22 
23 struct i2c_litex_cfg {
24 	uint32_t write_addr;
25 	uint32_t read_addr;
26 };
27 
28 #define GET_I2C_CFG(dev)						     \
29 	((const struct i2c_litex_cfg *) dev->config)
30 
31 #define GET_I2C_BITBANG(dev)						     \
32 	((struct i2c_bitbang *) dev->data)
33 
set_bit(uint32_t addr,uint32_t bit,uint32_t val)34 static inline void set_bit(uint32_t addr, uint32_t bit, uint32_t val)
35 {
36 	uint32_t mask = BIT(bit);
37 
38 	if (val) {
39 		litex_write8(litex_read8(addr) | mask, addr);
40 	} else {
41 		litex_write8(litex_read8(addr) & ~mask, addr);
42 	}
43 }
44 
get_bit(uint32_t addr,uint32_t bit)45 static inline int get_bit(uint32_t addr, uint32_t bit)
46 {
47 	uint32_t mask = BIT(bit);
48 
49 	return !!(litex_read8(addr) & mask);
50 }
51 
i2c_litex_bitbang_set_scl(void * context,int state)52 static void i2c_litex_bitbang_set_scl(void *context, int state)
53 {
54 	const struct i2c_litex_cfg *config =
55 		(const struct i2c_litex_cfg *) context;
56 
57 	set_bit(config->write_addr, SCL_BIT_POS, state);
58 }
59 
i2c_litex_bitbang_set_sda(void * context,int state)60 static void i2c_litex_bitbang_set_sda(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, SDA_DIR_BIT_POS, SDA_DIR_OUTPUT);
66 	set_bit(config->write_addr, SDA_BIT_W_POS, state);
67 }
68 
i2c_litex_bitbang_get_sda(void * context)69 static int i2c_litex_bitbang_get_sda(void *context)
70 {
71 	const struct i2c_litex_cfg *config =
72 		(const struct i2c_litex_cfg *) context;
73 
74 	set_bit(config->write_addr, SDA_DIR_BIT_POS, SDA_DIR_INPUT);
75 	return get_bit(config->read_addr, SDA_BIT_R_POS);
76 }
77 
78 static const struct i2c_bitbang_io i2c_litex_bitbang_io = {
79 	.set_scl = i2c_litex_bitbang_set_scl,
80 	.set_sda = i2c_litex_bitbang_set_sda,
81 	.get_sda = i2c_litex_bitbang_get_sda,
82 };
83 
i2c_litex_init(const struct device * dev)84 static int i2c_litex_init(const struct device *dev)
85 {
86 	const struct i2c_litex_cfg *config = GET_I2C_CFG(dev);
87 	struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
88 
89 	litex_write8(litex_read8(config->write_addr) | HIGH_STATE_ON_I2C_LINES, config->write_addr);
90 	i2c_bitbang_init(bitbang, &i2c_litex_bitbang_io, (void *)config);
91 
92 	return 0;
93 }
94 
i2c_litex_configure(const struct device * dev,uint32_t dev_config)95 static int i2c_litex_configure(const struct device *dev, uint32_t dev_config)
96 {
97 	struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
98 
99 	return i2c_bitbang_configure(bitbang, dev_config);
100 }
101 
i2c_litex_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)102 static int i2c_litex_transfer(const struct device *dev,  struct i2c_msg *msgs,
103 			      uint8_t num_msgs, uint16_t addr)
104 {
105 	struct i2c_bitbang *bitbang = GET_I2C_BITBANG(dev);
106 
107 	return i2c_bitbang_transfer(bitbang, msgs, num_msgs, addr);
108 }
109 
110 static const struct i2c_driver_api i2c_litex_driver_api = {
111 	.configure         = i2c_litex_configure,
112 	.transfer          = i2c_litex_transfer,
113 };
114 
115 /* Device Instantiation */
116 
117 #define I2C_LITEX_INIT(n)						       \
118 	static const struct i2c_litex_cfg i2c_litex_cfg_##n = {		       \
119 		.write_addr = DT_INST_REG_ADDR_BY_NAME(n, write),	       \
120 		.read_addr = DT_INST_REG_ADDR_BY_NAME(n, read),		       \
121 	};								       \
122 									       \
123 	static struct i2c_bitbang i2c_bitbang_##n;			       \
124 									       \
125 	I2C_DEVICE_DT_INST_DEFINE(n,					       \
126 			   i2c_litex_init,				       \
127 			   NULL,					       \
128 			   &i2c_bitbang_##n,	                               \
129 			   &i2c_litex_cfg_##n,				       \
130 			   POST_KERNEL,					       \
131 			   CONFIG_I2C_INIT_PRIORITY,			       \
132 			   &i2c_litex_driver_api			       \
133 			   );
134 
135 DT_INST_FOREACH_STATUS_OKAY(I2C_LITEX_INIT)
136