1.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4730.h Sun Jan 31 22:47:14 2021 +0100
1.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4730.h Tue Feb 16 22:53:31 2021 +0100
1.3 @@ -31,6 +31,22 @@
1.4 #include <l4/devices/cpm-jz4730.h>
1.5 #include <l4/devices/hw_mmio_register_block.h>
1.6
1.7 +
1.8 +
1.9 +// State machine states.
1.10 +
1.11 +enum I2c_jz4730_state
1.12 +{
1.13 + I2c_jz4730_end = 0,
1.14 + I2c_jz4730_pre_start,
1.15 + I2c_jz4730_start_read,
1.16 + I2c_jz4730_perform_read,
1.17 + I2c_jz4730_perform_write,
1.18 + I2c_jz4730_stop_write
1.19 +};
1.20 +
1.21 +
1.22 +
1.23 // I2C channel.
1.24
1.25 class I2c_jz4730_channel
1.26 @@ -54,6 +70,21 @@
1.27 protected:
1.28 void set_frequency();
1.29
1.30 + // State machine activities.
1.31 +
1.32 + unsigned int _nread, _nwritten, _length, _limit;
1.33 + uint8_t _address;
1.34 + uint8_t *_buf;
1.35 + bool _read;
1.36 +
1.37 + void communicate();
1.38 +
1.39 + enum I2c_jz4730_state pre_start();
1.40 + enum I2c_jz4730_state start_read();
1.41 + enum I2c_jz4730_state perform_read();
1.42 + enum I2c_jz4730_state perform_write();
1.43 + enum I2c_jz4730_state stop_write();
1.44 +
1.45 // Transaction control.
1.46
1.47 bool set_address(uint8_t address, bool read);
2.1 --- a/pkg/devices/lib/i2c/src/jz4730.cc Sun Jan 31 22:47:14 2021 +0100
2.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Tue Feb 16 22:53:31 2021 +0100
2.3 @@ -133,31 +133,192 @@
2.4 _regs[I2c_clock] = division;
2.5 }
2.6
2.7 -// Present the address on the bus.
2.8 +// State machine controller.
2.9
2.10 -bool
2.11 -I2c_jz4730_channel::set_address(uint8_t address, bool read)
2.12 +void
2.13 +I2c_jz4730_channel::communicate()
2.14 {
2.15 - // Waiting for long enough may eliminate a busy condition and thus permit a
2.16 - // new transaction. 10ms appears to be long enough, whereas 1ms does not
2.17 - // appear to be. In case this is insufficient, permit failure.
2.18 -
2.19 - unsigned int limit = 10;
2.20 + enum I2c_jz4730_state state = I2c_jz4730_pre_start;
2.21 + _limit = 10;
2.22
2.23 do
2.24 {
2.25 - if (!wait_for_irq(1000) && !(--limit))
2.26 - return false;
2.27 + wait_for_irq(1000);
2.28 +
2.29 + switch (state)
2.30 + {
2.31 + case I2c_jz4730_pre_start:
2.32 + state = pre_start();
2.33 + break;
2.34 +
2.35 + case I2c_jz4730_start_read:
2.36 + state = start_read();
2.37 + break;
2.38 +
2.39 + case I2c_jz4730_perform_read:
2.40 + state = perform_read();
2.41 + break;
2.42 +
2.43 + case I2c_jz4730_perform_write:
2.44 + state = perform_write();
2.45 + break;
2.46 +
2.47 + case I2c_jz4730_stop_write:
2.48 + state = stop_write();
2.49 + break;
2.50 +
2.51 + default:
2.52 + break;
2.53 + }
2.54 }
2.55 - while (busy());
2.56 + while (state != I2c_jz4730_end);
2.57 +}
2.58 +
2.59 +// State machine implementation handlers.
2.60 +
2.61 +// Assert not busy state, issue start, present the address on the bus.
2.62 +
2.63 +enum I2c_jz4730_state
2.64 +I2c_jz4730_channel::pre_start()
2.65 +{
2.66 + // Wait again if busy up to the limit.
2.67 +
2.68 + if (busy())
2.69 + {
2.70 + if (!(--_limit))
2.71 + return I2c_jz4730_end;
2.72 + else
2.73 + return I2c_jz4730_pre_start;
2.74 + }
2.75 +
2.76 + // Use a longer time limit in subsequent activities.
2.77 +
2.78 + _limit = 1000;
2.79 +
2.80 + // Start, send address, proceed to the operation.
2.81
2.82 start();
2.83
2.84 - _regs[I2c_data] = (address << 1) | (read ? 1 : 0);
2.85 + _regs[I2c_data] = (_address << 1) | (_read ? 1 : 0);
2.86
2.87 send_next();
2.88
2.89 - return true;
2.90 + return _read ? I2c_jz4730_start_read : I2c_jz4730_perform_write;
2.91 +}
2.92 +
2.93 +// Wait for an opportunity to begin reading.
2.94 +
2.95 +enum I2c_jz4730_state
2.96 +I2c_jz4730_channel::start_read()
2.97 +{
2.98 + // Wait again if not ready to read.
2.99 +
2.100 + if (transferring() || (!data_valid() && !nack()))
2.101 + return I2c_jz4730_start_read;
2.102 +
2.103 + return I2c_jz4730_perform_read;
2.104 +}
2.105 +
2.106 +// Attempt to read from the device.
2.107 +
2.108 +enum I2c_jz4730_state
2.109 +I2c_jz4730_channel::perform_read()
2.110 +{
2.111 + // Wait again if no available data.
2.112 +
2.113 + if (!data_valid() && !nack())
2.114 + {
2.115 + if (!(--_limit))
2.116 + {
2.117 + stop();
2.118 + return I2c_jz4730_end;
2.119 + }
2.120 + else
2.121 + return I2c_jz4730_perform_read;
2.122 + }
2.123 +
2.124 + // Stop if NACK received.
2.125 +
2.126 + if (nack())
2.127 + {
2.128 + stop();
2.129 + return I2c_jz4730_end;
2.130 + }
2.131 +
2.132 + // Signal last byte if appropriate.
2.133 +
2.134 + if ((!_nread && (_length == 1)) || (_nread == _length - 2))
2.135 + signal_last();
2.136 +
2.137 + // Store and solicit data.
2.138 +
2.139 + _buf[_nread++] = _regs[I2c_data];
2.140 + clear_next();
2.141 +
2.142 + // Stop if all data received.
2.143 +
2.144 + if (_nread >= _length)
2.145 + {
2.146 + stop();
2.147 + return I2c_jz4730_end;
2.148 + }
2.149 +
2.150 + // Wait for more data otherwise.
2.151 +
2.152 + _limit = 1000;
2.153 + return I2c_jz4730_perform_read;
2.154 +}
2.155 +
2.156 +// Attempt to write to the device.
2.157 +
2.158 +enum I2c_jz4730_state
2.159 +I2c_jz4730_channel::perform_write()
2.160 +{
2.161 + // Wait for data (address or previous data) to be sent.
2.162 +
2.163 + if (data_valid() && !nack())
2.164 + {
2.165 + if (!(--_limit))
2.166 + {
2.167 + stop();
2.168 + return I2c_jz4730_end;
2.169 + }
2.170 + else
2.171 + return I2c_jz4730_perform_write;
2.172 + }
2.173 +
2.174 + // Stop if all data written or NACK received.
2.175 +
2.176 + if ((_nwritten >= _length) || nack())
2.177 + {
2.178 + stop();
2.179 + _limit = 1000;
2.180 + return I2c_jz4730_stop_write;
2.181 + }
2.182 +
2.183 + // Write more data.
2.184 +
2.185 + _regs[I2c_data] = _buf[_nwritten++];
2.186 + send_next();
2.187 +
2.188 + // Wait for the data to be sent.
2.189 +
2.190 + _limit = 1000;
2.191 + return I2c_jz4730_perform_write;
2.192 +}
2.193 +
2.194 +// Terminate the write transaction.
2.195 +
2.196 +enum I2c_jz4730_state
2.197 +I2c_jz4730_channel::stop_write()
2.198 +{
2.199 + if (!transferred())
2.200 + {
2.201 + if (--_limit)
2.202 + return I2c_jz4730_stop_write;
2.203 + }
2.204 +
2.205 + return I2c_jz4730_end;
2.206 }
2.207
2.208 // Wait up to the given timeout (in microseconds) for an interrupt request,
2.209 @@ -174,54 +335,15 @@
2.210 unsigned int
2.211 I2c_jz4730_channel::read(uint8_t address, uint8_t buf[], unsigned int length)
2.212 {
2.213 - unsigned int nread = 0;
2.214 -
2.215 - if (!set_address(address, true))
2.216 - return 0;
2.217 -
2.218 - // Wait for an opportunity to begin reading.
2.219 -
2.220 - do
2.221 - {
2.222 - if (!wait_for_irq(1000000))
2.223 - printf("start (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.224 - }
2.225 - while (transferring() || (!data_valid() && !nack()));
2.226 -
2.227 - // Device apparently unavailable.
2.228 -
2.229 - if (nack())
2.230 - {
2.231 - stop();
2.232 - return nread;
2.233 - }
2.234 -
2.235 - // Attempt to read from the device.
2.236 + _nread = 0;
2.237 + _length = length;
2.238 + _address = address;
2.239 + _buf = &buf[0];
2.240 + _read = true;
2.241
2.242 - while (nread < length)
2.243 - {
2.244 - do
2.245 - {
2.246 - if (!wait_for_irq(1000000))
2.247 - {
2.248 - stop();
2.249 - return nread;
2.250 - }
2.251 - }
2.252 - while (!data_valid() && !nack());
2.253 + communicate();
2.254
2.255 - if (nack())
2.256 - break;
2.257 -
2.258 - if ((!nread && (length == 1)) || (nread == length - 2))
2.259 - signal_last();
2.260 -
2.261 - buf[nread++] = _regs[I2c_data];
2.262 - clear_next();
2.263 - }
2.264 -
2.265 - stop();
2.266 - return nread;
2.267 + return _nread;
2.268 }
2.269
2.270 // Write data to the bus.
2.271 @@ -229,49 +351,15 @@
2.272 unsigned int
2.273 I2c_jz4730_channel::write(uint8_t address, uint8_t buf[], unsigned int length)
2.274 {
2.275 - unsigned int nwritten = 0;
2.276 -
2.277 - if (!set_address(address, false))
2.278 - return 0;
2.279 -
2.280 - do
2.281 - {
2.282 - if (!wait_for_irq(1000000))
2.283 - {
2.284 - printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.285 - stop();
2.286 - return nwritten;
2.287 - }
2.288 - }
2.289 - while (data_valid() && !nack());
2.290 -
2.291 - while ((nwritten < length) && !nack())
2.292 - {
2.293 - _regs[I2c_data] = buf[nwritten++];
2.294 - send_next();
2.295 + _nwritten = 0;
2.296 + _length = length;
2.297 + _address = address;
2.298 + _buf = &buf[0];
2.299 + _read = false;
2.300
2.301 - do
2.302 - {
2.303 - if (!wait_for_irq(1000000))
2.304 - {
2.305 - printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.306 - stop();
2.307 - return nwritten;
2.308 - }
2.309 - }
2.310 - while (data_valid() && !nack());
2.311 - }
2.312 + communicate();
2.313
2.314 - stop();
2.315 -
2.316 - do
2.317 - {
2.318 - if (!wait_for_irq(1000000))
2.319 - break;
2.320 - }
2.321 - while (!transferred());
2.322 -
2.323 - return nwritten;
2.324 + return _nwritten;
2.325 }
2.326
2.327 // Test for data validity.