I2C properly works, finally

This commit is contained in:
Triss 2021-06-17 15:45:59 +02:00
parent 1cadae03df
commit 6cc617fe1f
5 changed files with 369 additions and 225 deletions

View File

@ -185,6 +185,7 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC)
- https://github.com/derekmulcahy/xvcpi - https://github.com/derekmulcahy/xvcpi
- OpenOCD as XVC client?? - OpenOCD as XVC client??
- [ ] Maybe use the ADCs for something? - [ ] Maybe use the ADCs for something?
- [ ] General generic manual GPIO mode
- [ ] SD/MMC/SDIO (will be a pain) - [ ] SD/MMC/SDIO (will be a pain)
- [ ] SUMP logic analyzer????? - [ ] SUMP logic analyzer?????
- see also [this](https://github.com/perexg/picoprobe-sump) - see also [this](https://github.com/perexg/picoprobe-sump)

View File

@ -10,224 +10,349 @@
#include "pinout.h" #include "pinout.h"
#include "i2ctinyusb.h" #include "i2ctinyusb.h"
// replicating/rewriting some SDK functions because they don't do what I want //static int delay = 10, delay2 = 5;
// except better this time //
//// I2C bitbang reimpl because ugh, synopsys
static int i2cex_probe_address(uint16_t addr, bool a10bit) { //// (mostly inspired by original I2CTinyUSB AVR firmware)
// TODO: bitbang the whole thing because the synopsys stuff sucks //__attribute__((__always_inline__)) inline static void i2cio_set_sda(bool hi) {
return PICO_ERROR_GENERIC; // if (hi) {
} // sio_hw->gpio_oe_clr = (1<<PINOUT_I2C_SDA); // SDA is input
// // => pullup configured, so it'll go high
static void i2cex_abort_xfer(void) { // } else {
// now do the abort // sio_hw->gpio_oe_set = (1<<PINOUT_I2C_SDA); // SDA is output
i2c->hw->enable = 1 /*| (1<<2)*/ | (1<<1); // sio_hw->gpio_clr = (1<<PINOUT_I2C_SDA); // and drive it low
// wait for M_TX_ABRT irq // }
do { //}
/*if (timeout_check) { //__attribute__((__always_inline__)) inline static bool i2cio_get_sda(void) {
timeout = timeout_check(ts); // return (sio_hw->gpio_in & (1<<PINOUT_I2C_SDA)) != 0;
abort |= timeout; //}
}*/ //__attribute__((__always_inline__)) inline static void i2cio_set_scl(bool hi) {
tight_loop_contents(); // busy_wait_us_32(delay2);
} while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS)); // sio_hw->gpio_oe_set = (1<<PINOUT_I2C_SCL); // SCL is output
// reset irq // if (hi)
//if (!timeout) // sio_hw->gpio_set = (1<<PINOUT_I2C_SCL); // SCL is high
(void)i2c->hw->clr_tx_abrt; // else
} // sio_hw->gpio_clr = (1<<PINOUT_I2C_SCL); // SCL is low
// busy_wait_us_32(delay2);
static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, //}
const uint8_t* src, size_t len, bool nostop, absolute_time_t until) { //
timeout_state_t ts_; //__attribute__((__always_inline__)) inline static void i2cio_scl_toggle(void) {
struct timeout_state* ts = &ts_; // i2cio_set_scl(true );
check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); // i2cio_set_scl(false);
//}
if ((int)len < 0) return PICO_ERROR_GENERIC; //
if (a10bit) { // addr too high //static void __no_inline_not_in_flash_func(i2cio_start)(void) { // start condition
if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; // i2cio_set_sda(false);
} else if (addr & 0x80) // i2cio_set_scl(false);
return PICO_ERROR_GENERIC; //}
//static void __no_inline_not_in_flash_func(i2cio_repstart)(void) { // repstart condition
if (len == 0) return i2cex_probe_address(addr, a10bit); // i2cio_set_sda(true);
// i2cio_set_scl(true);
bool abort = false, timeout = false; //
uint32_t abort_reason = 0; // i2cio_set_sda(false);
int byte_ctr; // i2cio_set_scl(false);
//}
i2c->hw->enable = 0; //static void __no_inline_not_in_flash_func(i2cio_stop)(void) { // stop condition
// enable 10bit mode if requested // i2cio_set_sda(false);
hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit // i2cio_set_scl(true );
? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS // i2cio_set_sda(true );
: I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); //}
i2c->hw->tar = addr; //
i2c->hw->enable = 1; //static bool __no_inline_not_in_flash_func(i2cio_write7)(uint8_t v) { // return value: acked? // needed for 10bitaddr xfers
// for (int i = 6; i >= 0; --i) {
for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { // i2cio_set_sda((v & (1<<i)) != 0);
bool first = byte_ctr == 0, // i2cio_scl_toggle();
last = byte_ctr == (int)len - 1; // }
//
i2c->hw->data_cmd = // i2cio_set_sda(true);
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | // i2cio_set_scl(true);
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | //
*src++; // bool ack = i2cio_get_sda();
// i2cio_set_scl(false);
do { //
if (timeout_check) { // return ack;
timeout = timeout_check(ts); //}
abort |= timeout; //static bool __no_inline_not_in_flash_func(i2cio_write8)(uint8_t v) { // return value: acked?
} // for (int i = 7; i >= 0; --i) {
tight_loop_contents(); // i2cio_set_sda((v & (1<<i)) != 0);
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); // i2cio_scl_toggle();
// }
if (!timeout) { //
abort_reason = i2c->hw->tx_abrt_source; // i2cio_set_sda(true);
if (abort_reason) { // i2cio_set_scl(true);
(void)i2c->hw->clr_tx_abrt; //
abort = true; // bool ack = i2cio_get_sda();
} // i2cio_set_scl(false);
//
if (abort || (last && !nostop)) { // return ack;
do { //}
if (timeout_check) { //static uint8_t __no_inline_not_in_flash_func(i2cio_read8)(bool last) {
timeout = timeout_check(ts); // i2cio_set_sda(true );
abort |= timeout; // i2cio_set_scl(false);
} //
tight_loop_contents(); // uint8_t rv = 0;
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS)); // for (int i = 7; i >= 0; --i) {
// i2cio_set_scl(true);
if (!timeout) (void)i2c->hw->clr_stop_det; // bool c = i2cio_get_sda();
} else { // rv <<= 1;
// if we had a timeout, send an abort request to the hardware, // if (c) rv |= 1;
// so that the bus gets released // i2cio_set_scl(false);
i2cex_abort_xfer(); // }
} //
} // if (last) i2cio_set_sda(true);
// else i2cio_set_sda(false);
if (abort) break; //
} // i2cio_scl_toggle();
// i2cio_set_sda(true);
int rval; //}
//
if (abort) { //// replicating/rewriting some SDK functions because they don't do what I want
const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS //// so I'm making better ones
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS //
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; //static int __no_inline_not_in_flash_func(i2cex_probe_address)(uint16_t addr, bool a10bit) {
// // I2C pins to SIO
if (timeout) rval = PICO_ERROR_TIMEOUT; // gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_SIO);
else if (!abort_reason || (abort_reason & addr_noack)) // gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_SIO);
rval = PICO_ERROR_GENERIC; //
else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) // int rv;
rval = byte_ctr; // i2cio_start();
else rval = PICO_ERROR_GENERIC; //
} else rval = byte_ctr; // if (a10bit) {
// // A10 magic higher 2 addr bits r/#w bit
i2c->restart_on_next = nostop; // uint8_t addr1 = 0x70 | (((addr >> 8) & 3) << 1) | 0,
return rval; // addr2 = addr & 0xff;
} //
static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, // if (i2cio_write7(addr1)) {
uint8_t* dst, size_t len, bool nostop, absolute_time_t until) { // if (i2cio_write8(addr2)) rv = 0;
timeout_state_t ts_; // else rv = PICO_ERROR_GENERIC;
struct timeout_state* ts = &ts_; // } else rv = PICO_ERROR_GENERIC;
check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); // } else {
// if (i2cio_write8((addr << 1) & 0xff)) rv = 0; // acked: ok
if ((int)len < 0) return PICO_ERROR_GENERIC; // else rv = PICO_ERROR_GENERIC; // nak :/
if (a10bit) { // addr too high // }
if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; // i2cio_stop();
} else if (addr & 0x80) //
return PICO_ERROR_GENERIC; // // I2C back to I2C
// gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C);
i2c->hw->enable = 0; // gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C);
// enable 10bit mode if requested //
hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit // return rv;
? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS //}
: I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); //
i2c->hw->tar = addr; //static void i2cex_abort_xfer(i2c_inst_t* i2c) {
i2c->hw->enable = 1; // // now do the abort
// i2c->hw->enable = 1 /*| (1<<2)*/ | (1<<1);
if (len == 0) return i2cex_probe_address(addr, a10bit); // // wait for M_TX_ABRT irq
// do {
bool abort = false, timeout = false; // /*if (timeout_check) {
uint32_t abort_reason = 0; // timeout = timeout_check(ts);
int byte_ctr; // abort |= timeout;
// }*/
for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { // tight_loop_contents();
bool first = byte_ctr == 0; // } while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS));
bool last = byte_ctr == (int)len - 1; // // reset irq
// //if (!timeout)
while (!i2c_get_write_available(i2c) && !abort) { // (void)i2c->hw->clr_tx_abrt;
tight_loop_contents(); //}
// ? //
if (timeout_check) { //static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
timeout = timeout_check(ts); // const uint8_t* src, size_t len, bool nostop, absolute_time_t until) {
abort |= timeout; // timeout_state_t ts_;
} // struct timeout_state* ts = &ts_;
} // check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until);
//
if (timeout) { // if ((int)len < 0) return PICO_ERROR_GENERIC;
// if we had a timeout, send an abort request to the hardware, // if (a10bit) { // addr too high
// so that the bus gets released // if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC;
i2cex_abort_xfer(); // } else if (addr & 0x80)
} // return PICO_ERROR_GENERIC;
if (abort) break; //
// if (len == 0) return i2cex_probe_address(addr, a10bit);
i2c->hw->data_cmd = //
bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | // bool abort = false, timeout = false;
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | // uint32_t abort_reason = 0;
I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read // int byte_ctr;
//
do { // i2c->hw->enable = 0;
abort_reason = i2c->hw->tx_abrt_source; // // enable 10bit mode if requested
abort = (bool)i2c->hw->clr_tx_abrt; // hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit
// ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS
if (timeout_check) { // : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB);
timeout = timeout_check(ts); // i2c->hw->tar = addr;
abort |= timeout; // i2c->hw->enable = 1;
} //
tight_loop_contents(); // ? // for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) {
} while (!abort && !i2c_get_read_available(i2c)); // bool first = byte_ctr == 0,
// last = byte_ctr == (int)len - 1;
if (timeout) { //
// if we had a timeout, send an abort request to the hardware, // i2c->hw->data_cmd =
// so that the bus gets released // bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
i2cex_abort_xfer(); // bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
} // *src++;
if (abort) break; //
// do {
*dst++ = (uint8_t)i2c->hw->data_cmd; // if (timeout_check) {
} // timeout = timeout_check(ts);
// abort |= timeout;
int rval; // }
// tight_loop_contents();
if (abort) { // } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS));
const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS //
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS // if (!timeout) {
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; // abort_reason = i2c->hw->tx_abrt_source;
// if (abort_reason) {
if (timeout) rval = PICO_ERROR_TIMEOUT; // (void)i2c->hw->clr_tx_abrt;
else if (!abort_reason || (abort_reason & addr_noack)) // abort = true;
rval = PICO_ERROR_GENERIC; // }
else rval = PICO_ERROR_GENERIC; //
} else rval = byte_ctr; // if (abort || (last && !nostop)) {
// do {
i2c->restart_on_next = nostop; // if (timeout_check) {
return rval; // timeout = timeout_check(ts);
} // abort |= timeout;
static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, // }
const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) { // tight_loop_contents();
absolute_time_t t = make_timeout_time_us(timeout_us); // } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS));
return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t); //
} // if (!timeout) (void)i2c->hw->clr_stop_det;
static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, // else
uint8_t* dst, size_t len, bool nostop, uint32_t timeout_us) { // // if we had a timeout, send an abort request to the hardware,
absolute_time_t t = make_timeout_time_us(timeout_us); // // so that the bus gets released
return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t); // i2cex_abort_xfer(i2c);
} // }
// } else i2cex_abort_xfer(i2c);
//
// if (abort) break;
// }
//
// int rval;
//
// if (abort) {
// const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS
// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS
// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS;
//
// if (timeout) rval = PICO_ERROR_TIMEOUT;
// else if (!abort_reason || (abort_reason & addr_noack))
// rval = PICO_ERROR_GENERIC;
// else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS)
// rval = byte_ctr;
// else rval = PICO_ERROR_GENERIC;
// } else rval = byte_ctr;
//
// i2c->restart_on_next = nostop;
// return rval;
//}
//static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
// uint8_t* dst, size_t len, bool nostop, absolute_time_t until) {
// timeout_state_t ts_;
// struct timeout_state* ts = &ts_;
// check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until);
//
// if ((int)len < 0) return PICO_ERROR_GENERIC;
// if (a10bit) { // addr too high
// if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC;
// } else if (addr & 0x80)
// return PICO_ERROR_GENERIC;
//
// i2c->hw->enable = 0;
// // enable 10bit mode if requested
// hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit
// ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS
// : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB);
// i2c->hw->tar = addr;
// i2c->hw->enable = 1;
//
// if (len == 0) return i2cex_probe_address(addr, a10bit);
//
// bool abort = false, timeout = false;
// uint32_t abort_reason = 0;
// int byte_ctr;
//
// for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) {
// bool first = byte_ctr == 0;
// bool last = byte_ctr == (int)len - 1;
//
// while (!i2c_get_write_available(i2c) && !abort) {
// tight_loop_contents();
// // ?
// if (timeout_check) {
// timeout = timeout_check(ts);
// abort |= timeout;
// }
// }
//
// if (timeout) {
// // if we had a timeout, send an abort request to the hardware,
// // so that the bus gets released
// i2cex_abort_xfer(i2c);
// }
// if (abort) break;
//
// i2c->hw->data_cmd =
// bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
// bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
// I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read
//
// do {
// abort_reason = i2c->hw->tx_abrt_source;
// abort = (bool)i2c->hw->clr_tx_abrt;
//
// if (timeout_check) {
// timeout = timeout_check(ts);
// abort |= timeout;
// }
// tight_loop_contents(); // ?
// } while (!abort && !i2c_get_read_available(i2c));
//
// if (timeout) {
// // if we had a timeout, send an abort request to the hardware,
// // so that the bus gets released
// i2cex_abort_xfer(i2c);
// }
// if (abort) break;
//
// *dst++ = (uint8_t)i2c->hw->data_cmd;
// }
//
// int rval;
//
// if (abort) {
// const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS
// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS
// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS;
//
// if (timeout) rval = PICO_ERROR_TIMEOUT;
// else if (!abort_reason || (abort_reason & addr_noack))
// rval = PICO_ERROR_GENERIC;
// else rval = PICO_ERROR_GENERIC;
// } else rval = byte_ctr;
//
// i2c->restart_on_next = nostop;
// return rval;
//}
//static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
// const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) {
// absolute_time_t t = make_timeout_time_us(timeout_us);
// return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t);
//}
//static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
// uint8_t* dst, size_t len, bool nostop, uint32_t timeout_us) {
// absolute_time_t t = make_timeout_time_us(timeout_us);
// return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t);
//}
__attribute__((__const__)) __attribute__((__const__))
enum ki2c_funcs i2ctu_get_func(void) { enum ki2c_funcs i2ctu_get_func(void) {
// TODO: 10bit addresses
// TODO: SMBUS_EMUL_ALL => I2C_M_RECV_LEN
// TODO: maybe also PROTOCOL_MANGLING, NOSTART
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} }
void i2ctu_init(void) { void i2ctu_init(void) {
// default to 100 kHz (SDK example default so should be ok) // default to 100 kHz (SDK example default so should be ok)
//delay = 10; delay2 = 5;
i2c_init(PINOUT_I2C_DEV, 100*1000); i2c_init(PINOUT_I2C_DEV, 100*1000);
gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C);
@ -238,22 +363,43 @@ void i2ctu_init(void) {
bi_decl(bi_2pins_with_func(PINOUT_I2C_SCL, PINOUT_I2C_SDA, GPIO_FUNC_I2C)); bi_decl(bi_2pins_with_func(PINOUT_I2C_SCL, PINOUT_I2C_SDA, GPIO_FUNC_I2C));
} }
uint32_t i2ctu_set_freq(uint32_t freq) { uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us) {
//delay = us;
//delay2 = us >> 1;
//if (!delay2) delay2 = 1;
return i2c_set_baudrate(PINOUT_I2C_DEV, freq); return i2c_set_baudrate(PINOUT_I2C_DEV, freq);
} }
enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags,
uint16_t addr, const uint8_t* buf, size_t len) { uint16_t addr, const uint8_t* buf, size_t len) {
int rv = i2cex_write_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len, if (len == 0) {
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); // do a read, that's less hazardous
if (rv < 0) return ITU_STATUS_ADDR_NAK; uint8_t stuff = 0;
return ITU_STATUS_ADDR_ACK; int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr/*&0x7f*/, /*false,*/ &stuff, 1,
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
if (rv < 0) return ITU_STATUS_ADDR_NAK;
return ITU_STATUS_ADDR_ACK;
} else {
int rv = i2c_write_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len,
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK;
return ITU_STATUS_ADDR_ACK;
}
} }
enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags, enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags,
uint16_t addr, uint8_t* buf, size_t len) { uint16_t addr, uint8_t* buf, size_t len) {
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len, if (len == 0) {
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); uint8_t stuff = 0;
if (rv < 0) return ITU_STATUS_ADDR_NAK; int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ &stuff, 1,
return ITU_STATUS_ADDR_ACK; !(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
if (rv < 0) return ITU_STATUS_ADDR_NAK;
return ITU_STATUS_ADDR_ACK;
} else {
int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len,
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK;
return ITU_STATUS_ADDR_ACK;
}
} }

View File

@ -136,7 +136,7 @@ static u32 usb_func(struct i2c_adapter *adapter)
} }
ret = le32_to_cpup(pfunc); ret = le32_to_cpup(pfunc);
dev_warn(&adapter->dev, "itu func=%08x\n", ret); //dev_warn(&adapter->dev, "itu func=%08x\n", ret);
out: out:
kfree(pfunc); kfree(pfunc);
return ret; return ret;

View File

@ -95,7 +95,7 @@ struct itu_cmd {
__attribute__((__const__)) __attribute__((__const__))
enum ki2c_funcs i2ctu_get_func(void); enum ki2c_funcs i2ctu_get_func(void);
void i2ctu_init(void); void i2ctu_init(void);
uint32_t i2ctu_set_freq(uint32_t freq); // returns selected frequency, or 0 on error uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us); // returns selected frequency, or 0 on error
enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags,
uint16_t addr, const uint8_t* buf, size_t len); uint16_t addr, const uint8_t* buf, size_t len);
enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags, enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags,

View File

@ -91,7 +91,7 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
uint32_t us = req->wValue ? req->wValue : 1; uint32_t us = req->wValue ? req->wValue : 1;
uint32_t freq = 1000*1000 / us; uint32_t freq = 1000*1000 / us;
if (i2ctu_set_freq(freq) != 0) // returned an ok frequency if (i2ctu_set_freq(freq, us) != 0) // returned an ok frequency
return tud_control_status(rhport, req); return tud_control_status(rhport, req);
else return false; else return false;
} }
@ -128,9 +128,6 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
} else { // write } else { // write
bool rv = tud_control_xfer(rhport, req, buf, cmd.len); bool rv = tud_control_xfer(rhport, req, buf, cmd.len);
if (rv) { if (rv) {
uint8_t val = cmd.cmd;
i2c_write_timeout_us(PINOUT_I2C_DEV, cmd.len, &val, 1, false, 1000*1000);
state = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, state = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, buf, sizeof buf); cmd.addr, buf, sizeof buf);
} }