diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c')
-rw-r--r-- | c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c | 398 |
1 files changed, 0 insertions, 398 deletions
diff --git a/c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c b/c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c deleted file mode 100644 index bace7e656e..0000000000 --- a/c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (c) 2016 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <bsp/atsam-clock-config.h> -#include <bsp/atsam-i2c.h> - -#include <rtems/irq-extension.h> - -#define ATSAMV_I2C_IRQ_ERROR \ - (TWIHS_IDR_ARBLST \ - | TWIHS_IDR_TOUT \ - | TWIHS_IDR_OVRE \ - | TWIHS_IDR_UNRE \ - | TWIHS_IDR_NACK) - -#define TEN_BIT_MASK 0xFC00 -#define SEVEN_BIT_MASK 0xFF80 -#define TEN_BIT_START_ADDR_MASK 0x78 -#define LAST_TWO_BITS_MASK 0x03 -#define LAST_BYTE_MASK 0x00FF - -static void -atsam_i2c_disable_interrupts(Twihs *regs) -{ - regs->TWIHS_IDR = 0xFFFFFFFF; -} - -static void -atsam_i2c_set_transfer_status(transfer_desc *trans_desc, transfer_state state) -{ - trans_desc->trans_state = state; -} - -static void -atsam_i2c_continue_read(Twihs *regs, transfer_desc *trans_desc) -{ - trans_desc->data[trans_desc->already_transferred] = TWI_ReadByte(regs); - trans_desc->already_transferred++; - - /* check for transfer finish */ - if (trans_desc->already_transferred == trans_desc->data_size) { - if (trans_desc->stop_request){ - TWI_DisableIt(regs, TWIHS_IDR_RXRDY); - TWI_EnableIt(regs, TWIHS_IER_TXCOMP); - atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT); - } else { - atsam_i2c_set_transfer_status(trans_desc, RX_CONT_MESSAGE_NEEDED); - } - } - /* Last byte? */ - else if ((trans_desc->already_transferred == (trans_desc->data_size - 1)) - && (trans_desc->stop_request)){ - TWI_Stop(regs); - } -} - -static bool -atsam_i2c_is_state(transfer_desc *trans_desc, transfer_state state) -{ - return (trans_desc->trans_state == state); -} - -static void -atsam_i2c_continue_write(Twihs *regs, transfer_desc *trans_desc) -{ - /* Transfer finished ? */ - if (trans_desc->already_transferred == trans_desc->data_size) { - TWI_DisableIt(regs, TWIHS_IDR_TXRDY); - if (trans_desc->stop_request){ - TWI_EnableIt(regs, TWIHS_IER_TXCOMP); - TWI_SendSTOPCondition(regs); - atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT); - } else { - atsam_i2c_set_transfer_status(trans_desc, TX_CONT_MESSAGE_NEEDED); - } - } - /* Bytes remaining */ - else { - TWI_WriteByte(regs, - trans_desc->data[trans_desc->already_transferred]); - trans_desc->already_transferred++; - } -} - -static void -atsam_i2c_finish_write_transfer(Twihs *regs, transfer_desc *trans_desc) -{ - TWI_ReadByte(regs); - TWI_DisableIt(regs, TWIHS_IDR_TXCOMP); - trans_desc->status = 0; -} - -static void -atsam_i2c_next_packet(atsam_i2c_bus *bus) -{ - i2c_msg *msg; - - ++bus->msgs; - --bus->msg_todo; - - msg = &bus->msgs[0]; - - bus->current_msg_todo = msg->len; - bus->current_msg_byte = msg->buf; -} - -static void -atsam_i2c_set_td(atsam_i2c_bus *bus, uint32_t already_transferred, - bool stop_needed) -{ - transfer_desc *trans_desc = &bus->trans_desc; - - trans_desc->status = ASYNC_STATUS_PENDING; - trans_desc->data = bus->current_msg_byte; - trans_desc->data_size = bus->current_msg_todo; - trans_desc->already_transferred = already_transferred; - trans_desc->stop_request = stop_needed; -} - -static bool -atsam_i2c_set_address_size(const i2c_msg *msg) -{ - bool rv = ((msg->flags & I2C_M_TEN) == 0) ? false : true; - return rv; -} - -static void -atsam_i2c_set_address_regs(Twihs *regs, uint16_t address, bool ten_bit_addr, - bool read_transfer) -{ - /* No internal addresses used */ - uint32_t mmr_temp = 0; - uint32_t iadr_temp = 0; - - assert(regs != NULL); - if (ten_bit_addr){ - uint8_t addr_temp = TEN_BIT_START_ADDR_MASK; - assert(address & TEN_BIT_MASK); - mmr_temp = (1u << 8) | ((addr_temp & LAST_TWO_BITS_MASK) << 16); - iadr_temp = (addr_temp & LAST_BYTE_MASK); - } else { - assert((address & SEVEN_BIT_MASK) == 0); - mmr_temp = (address << 16); - } - - if (read_transfer){ - mmr_temp |= TWIHS_MMR_MREAD; - } - - /* Set slave and number of internal address bytes */ - regs->TWIHS_MMR = 0; - regs->TWIHS_MMR = mmr_temp; - - /* Set internal address bytes */ - regs->TWIHS_IADR = 0; - regs->TWIHS_IADR = iadr_temp; -} - -static void -atsam_i2c_setup_read_transfer(Twihs *regs, bool ctrl, uint16_t slave_addr, - bool send_stop) -{ - TWI_EnableIt(regs, TWIHS_IER_RXRDY); - atsam_i2c_set_address_regs(regs, slave_addr, ctrl, true); - if (send_stop){ - regs->TWIHS_CR = TWIHS_CR_START | TWIHS_CR_STOP; - } else { - regs->TWIHS_CR = TWIHS_CR_START; - } -} - -static void -atsam_i2c_setup_write_transfer(atsam_i2c_bus *bus, Twihs *regs, bool ctrl, - uint16_t slave_addr) -{ - atsam_i2c_set_address_regs(regs, slave_addr, ctrl, false); - TWI_WriteByte(regs, *bus->current_msg_byte); - TWI_EnableIt(regs, TWIHS_IER_TXRDY); -} - -static void -atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs) -{ - const i2c_msg *msgs = bus->msgs; - bool send_stop = false; - uint32_t msg_todo = bus->msg_todo; - uint16_t slave_addr; - bool ten_bit_addr = false; - uint32_t already_transferred; - bool stop_needed = true; - - ten_bit_addr = atsam_i2c_set_address_size(msgs); - - if ((msg_todo > 1) && ((msgs[1].flags & I2C_M_NOSTART) != 0)){ - stop_needed = false; - } - - bus->read = (msgs->flags & I2C_M_RD) != 0; - slave_addr = msgs->addr; - already_transferred = (bus->read == true) ? 0 : 1; - atsam_i2c_set_td(bus, already_transferred, stop_needed); - - transfer_desc *trans_desc = &bus->trans_desc; - - if (bus->read){ - if (bus->current_msg_todo == 1){ - send_stop = true; - } - atsam_i2c_set_transfer_status(trans_desc, RX_SEND_DATA); - atsam_i2c_setup_read_transfer(regs, ten_bit_addr, - slave_addr, send_stop); - } else { - atsam_i2c_set_transfer_status(trans_desc, TX_SEND_DATA); - atsam_i2c_setup_write_transfer(bus, regs, ten_bit_addr, - slave_addr); - } -} - -static void -atsam_i2c_interrupt(void *arg) -{ - atsam_i2c_bus *bus = arg; - uint32_t irqstatus; - bool done = false; - transfer_desc *trans_desc; - - Twihs *regs = bus->regs; - - /* read interrupts */ - irqstatus = regs->TWIHS_SR; - - if((irqstatus & (TWIHS_SR_ARBLST | TWIHS_SR_NACK)) != 0) { - done = true; - } - - trans_desc = &bus->trans_desc; - - if (((irqstatus & TWIHS_SR_RXRDY) != 0) && - (atsam_i2c_is_state(trans_desc, RX_SEND_DATA))){ - /* carry on read transfer */ - atsam_i2c_continue_read(regs, trans_desc); - } else if (((irqstatus & TWIHS_SR_TXCOMP) != 0) && - (atsam_i2c_is_state(trans_desc, TX_RX_STOP_SENT))){ - atsam_i2c_finish_write_transfer(regs, trans_desc); - done = true; - } else if (((irqstatus & TWIHS_SR_TXRDY) != 0) && - (atsam_i2c_is_state(trans_desc, TX_SEND_DATA))){ - atsam_i2c_continue_write(regs, trans_desc); - if (trans_desc->trans_state == TX_CONT_MESSAGE_NEEDED){ - done = true; - } - } - - if(done){ - uint32_t err = irqstatus & ATSAMV_I2C_IRQ_ERROR; - - atsam_i2c_next_packet(bus); - if (bus->msg_todo == 0 || err != 0) { - rtems_status_code sc; - - atsam_i2c_disable_interrupts(regs); - sc = rtems_event_transient_send(bus->task_id); - assert(sc == RTEMS_SUCCESSFUL); - } else { - atsam_i2c_setup_transfer(bus, regs); - } - } -} - -static int -atsam_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count) -{ - rtems_status_code sc; - atsam_i2c_bus *bus = (atsam_i2c_bus *)base; - Twihs *regs; - uint32_t i; - - rtems_task_wake_after(1); - - if (msg_count < 1){ - return 1; - } - - for (i = 0; i < msg_count; ++i) { - if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) { - return -EINVAL; - } - } - - bus->msgs = &msgs[0]; - bus->msg_todo = msg_count; - bus->current_msg_todo = msgs[0].len; - bus->current_msg_byte = msgs[0].buf; - bus->task_id = rtems_task_self(); - - regs = bus->regs; - - atsam_i2c_setup_transfer(bus, regs); - - regs->TWIHS_IER = ATSAMV_I2C_IRQ_ERROR; - - sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout); - if (sc != RTEMS_SUCCESSFUL){ - rtems_event_transient_clear(); - return -ETIMEDOUT; - } - - return 0; -} - -static int -atsam_i2c_set_clock(i2c_bus *base, unsigned long clock) -{ - atsam_i2c_bus *bus = (atsam_i2c_bus *)base; - Twihs *regs = bus->regs; - TWI_ConfigureMaster(regs, clock, BOARD_MCK); - return 0; -} - -static void -atsam_i2c_destroy(i2c_bus *base) -{ - atsam_i2c_bus *bus = (atsam_i2c_bus *)base; - rtems_status_code sc; - - sc = rtems_interrupt_handler_remove(bus->irq, atsam_i2c_interrupt, bus); - assert(sc == RTEMS_SUCCESSFUL); - - i2c_bus_destroy_and_free(&bus->base); -} - -static void -atsam_i2c_init(atsam_i2c_bus *bus, uint32_t input_clock, Twihs *board_base, - uint32_t board_id, const Pin *pins) -{ - - /* Initialize the TWI */ - PIO_Configure(pins, TWI_AMOUNT_PINS); - - /* Enable the TWI clock */ - ENABLE_PERIPHERAL(board_id); - - TWI_ConfigureMaster(board_base, input_clock, BOARD_MCK); -} - -int -i2c_bus_register_atsam( - const char *bus_path, - Twihs *register_base, - rtems_vector_number irq, - const Pin pins[TWI_AMOUNT_PINS] -) -{ - atsam_i2c_bus *bus; - rtems_status_code sc; - uint32_t board_id = (uint32_t) irq; - - bus = (atsam_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus)); - if (bus == NULL){ - return -1; - } - - bus->regs = register_base; - bus->irq = irq; - - atsam_i2c_init(bus, I2C_BUS_CLOCK_DEFAULT, bus->regs, - board_id, pins); - - sc = rtems_interrupt_handler_install( - irq, - "Atsamv_I2C", - RTEMS_INTERRUPT_UNIQUE, - atsam_i2c_interrupt, - bus - ); - if(sc != RTEMS_SUCCESSFUL){ - (*bus->base.destroy)(&bus->base); - - rtems_set_errno_and_return_minus_one(EIO); - } - - bus->base.transfer = atsam_i2c_transfer; - bus->base.set_clock = atsam_i2c_set_clock; - bus->base.destroy = atsam_i2c_destroy; - - return i2c_bus_register(&bus->base, bus_path); -} |