1.1 --- a/pkg/devices/lib/i2c/src/jz4730.cc Sun Jan 31 22:47:14 2021 +0100
1.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Tue Feb 16 22:53:31 2021 +0100
1.3 @@ -133,31 +133,192 @@
1.4 _regs[I2c_clock] = division;
1.5 }
1.6
1.7 -// Present the address on the bus.
1.8 +// State machine controller.
1.9
1.10 -bool
1.11 -I2c_jz4730_channel::set_address(uint8_t address, bool read)
1.12 +void
1.13 +I2c_jz4730_channel::communicate()
1.14 {
1.15 - // Waiting for long enough may eliminate a busy condition and thus permit a
1.16 - // new transaction. 10ms appears to be long enough, whereas 1ms does not
1.17 - // appear to be. In case this is insufficient, permit failure.
1.18 -
1.19 - unsigned int limit = 10;
1.20 + enum I2c_jz4730_state state = I2c_jz4730_pre_start;
1.21 + _limit = 10;
1.22
1.23 do
1.24 {
1.25 - if (!wait_for_irq(1000) && !(--limit))
1.26 - return false;
1.27 + wait_for_irq(1000);
1.28 +
1.29 + switch (state)
1.30 + {
1.31 + case I2c_jz4730_pre_start:
1.32 + state = pre_start();
1.33 + break;
1.34 +
1.35 + case I2c_jz4730_start_read:
1.36 + state = start_read();
1.37 + break;
1.38 +
1.39 + case I2c_jz4730_perform_read:
1.40 + state = perform_read();
1.41 + break;
1.42 +
1.43 + case I2c_jz4730_perform_write:
1.44 + state = perform_write();
1.45 + break;
1.46 +
1.47 + case I2c_jz4730_stop_write:
1.48 + state = stop_write();
1.49 + break;
1.50 +
1.51 + default:
1.52 + break;
1.53 + }
1.54 }
1.55 - while (busy());
1.56 + while (state != I2c_jz4730_end);
1.57 +}
1.58 +
1.59 +// State machine implementation handlers.
1.60 +
1.61 +// Assert not busy state, issue start, present the address on the bus.
1.62 +
1.63 +enum I2c_jz4730_state
1.64 +I2c_jz4730_channel::pre_start()
1.65 +{
1.66 + // Wait again if busy up to the limit.
1.67 +
1.68 + if (busy())
1.69 + {
1.70 + if (!(--_limit))
1.71 + return I2c_jz4730_end;
1.72 + else
1.73 + return I2c_jz4730_pre_start;
1.74 + }
1.75 +
1.76 + // Use a longer time limit in subsequent activities.
1.77 +
1.78 + _limit = 1000;
1.79 +
1.80 + // Start, send address, proceed to the operation.
1.81
1.82 start();
1.83
1.84 - _regs[I2c_data] = (address << 1) | (read ? 1 : 0);
1.85 + _regs[I2c_data] = (_address << 1) | (_read ? 1 : 0);
1.86
1.87 send_next();
1.88
1.89 - return true;
1.90 + return _read ? I2c_jz4730_start_read : I2c_jz4730_perform_write;
1.91 +}
1.92 +
1.93 +// Wait for an opportunity to begin reading.
1.94 +
1.95 +enum I2c_jz4730_state
1.96 +I2c_jz4730_channel::start_read()
1.97 +{
1.98 + // Wait again if not ready to read.
1.99 +
1.100 + if (transferring() || (!data_valid() && !nack()))
1.101 + return I2c_jz4730_start_read;
1.102 +
1.103 + return I2c_jz4730_perform_read;
1.104 +}
1.105 +
1.106 +// Attempt to read from the device.
1.107 +
1.108 +enum I2c_jz4730_state
1.109 +I2c_jz4730_channel::perform_read()
1.110 +{
1.111 + // Wait again if no available data.
1.112 +
1.113 + if (!data_valid() && !nack())
1.114 + {
1.115 + if (!(--_limit))
1.116 + {
1.117 + stop();
1.118 + return I2c_jz4730_end;
1.119 + }
1.120 + else
1.121 + return I2c_jz4730_perform_read;
1.122 + }
1.123 +
1.124 + // Stop if NACK received.
1.125 +
1.126 + if (nack())
1.127 + {
1.128 + stop();
1.129 + return I2c_jz4730_end;
1.130 + }
1.131 +
1.132 + // Signal last byte if appropriate.
1.133 +
1.134 + if ((!_nread && (_length == 1)) || (_nread == _length - 2))
1.135 + signal_last();
1.136 +
1.137 + // Store and solicit data.
1.138 +
1.139 + _buf[_nread++] = _regs[I2c_data];
1.140 + clear_next();
1.141 +
1.142 + // Stop if all data received.
1.143 +
1.144 + if (_nread >= _length)
1.145 + {
1.146 + stop();
1.147 + return I2c_jz4730_end;
1.148 + }
1.149 +
1.150 + // Wait for more data otherwise.
1.151 +
1.152 + _limit = 1000;
1.153 + return I2c_jz4730_perform_read;
1.154 +}
1.155 +
1.156 +// Attempt to write to the device.
1.157 +
1.158 +enum I2c_jz4730_state
1.159 +I2c_jz4730_channel::perform_write()
1.160 +{
1.161 + // Wait for data (address or previous data) to be sent.
1.162 +
1.163 + if (data_valid() && !nack())
1.164 + {
1.165 + if (!(--_limit))
1.166 + {
1.167 + stop();
1.168 + return I2c_jz4730_end;
1.169 + }
1.170 + else
1.171 + return I2c_jz4730_perform_write;
1.172 + }
1.173 +
1.174 + // Stop if all data written or NACK received.
1.175 +
1.176 + if ((_nwritten >= _length) || nack())
1.177 + {
1.178 + stop();
1.179 + _limit = 1000;
1.180 + return I2c_jz4730_stop_write;
1.181 + }
1.182 +
1.183 + // Write more data.
1.184 +
1.185 + _regs[I2c_data] = _buf[_nwritten++];
1.186 + send_next();
1.187 +
1.188 + // Wait for the data to be sent.
1.189 +
1.190 + _limit = 1000;
1.191 + return I2c_jz4730_perform_write;
1.192 +}
1.193 +
1.194 +// Terminate the write transaction.
1.195 +
1.196 +enum I2c_jz4730_state
1.197 +I2c_jz4730_channel::stop_write()
1.198 +{
1.199 + if (!transferred())
1.200 + {
1.201 + if (--_limit)
1.202 + return I2c_jz4730_stop_write;
1.203 + }
1.204 +
1.205 + return I2c_jz4730_end;
1.206 }
1.207
1.208 // Wait up to the given timeout (in microseconds) for an interrupt request,
1.209 @@ -174,54 +335,15 @@
1.210 unsigned int
1.211 I2c_jz4730_channel::read(uint8_t address, uint8_t buf[], unsigned int length)
1.212 {
1.213 - unsigned int nread = 0;
1.214 -
1.215 - if (!set_address(address, true))
1.216 - return 0;
1.217 -
1.218 - // Wait for an opportunity to begin reading.
1.219 -
1.220 - do
1.221 - {
1.222 - if (!wait_for_irq(1000000))
1.223 - printf("start (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
1.224 - }
1.225 - while (transferring() || (!data_valid() && !nack()));
1.226 -
1.227 - // Device apparently unavailable.
1.228 -
1.229 - if (nack())
1.230 - {
1.231 - stop();
1.232 - return nread;
1.233 - }
1.234 -
1.235 - // Attempt to read from the device.
1.236 + _nread = 0;
1.237 + _length = length;
1.238 + _address = address;
1.239 + _buf = &buf[0];
1.240 + _read = true;
1.241
1.242 - while (nread < length)
1.243 - {
1.244 - do
1.245 - {
1.246 - if (!wait_for_irq(1000000))
1.247 - {
1.248 - stop();
1.249 - return nread;
1.250 - }
1.251 - }
1.252 - while (!data_valid() && !nack());
1.253 + communicate();
1.254
1.255 - if (nack())
1.256 - break;
1.257 -
1.258 - if ((!nread && (length == 1)) || (nread == length - 2))
1.259 - signal_last();
1.260 -
1.261 - buf[nread++] = _regs[I2c_data];
1.262 - clear_next();
1.263 - }
1.264 -
1.265 - stop();
1.266 - return nread;
1.267 + return _nread;
1.268 }
1.269
1.270 // Write data to the bus.
1.271 @@ -229,49 +351,15 @@
1.272 unsigned int
1.273 I2c_jz4730_channel::write(uint8_t address, uint8_t buf[], unsigned int length)
1.274 {
1.275 - unsigned int nwritten = 0;
1.276 -
1.277 - if (!set_address(address, false))
1.278 - return 0;
1.279 -
1.280 - do
1.281 - {
1.282 - if (!wait_for_irq(1000000))
1.283 - {
1.284 - printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
1.285 - stop();
1.286 - return nwritten;
1.287 - }
1.288 - }
1.289 - while (data_valid() && !nack());
1.290 -
1.291 - while ((nwritten < length) && !nack())
1.292 - {
1.293 - _regs[I2c_data] = buf[nwritten++];
1.294 - send_next();
1.295 + _nwritten = 0;
1.296 + _length = length;
1.297 + _address = address;
1.298 + _buf = &buf[0];
1.299 + _read = false;
1.300
1.301 - do
1.302 - {
1.303 - if (!wait_for_irq(1000000))
1.304 - {
1.305 - printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
1.306 - stop();
1.307 - return nwritten;
1.308 - }
1.309 - }
1.310 - while (data_valid() && !nack());
1.311 - }
1.312 + communicate();
1.313
1.314 - stop();
1.315 -
1.316 - do
1.317 - {
1.318 - if (!wait_for_irq(1000000))
1.319 - break;
1.320 - }
1.321 - while (!transferred());
1.322 -
1.323 - return nwritten;
1.324 + return _nwritten;
1.325 }
1.326
1.327 // Test for data validity.