summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/atsam/i2c/atsam_i2c_bus.c
diff options
context:
space:
mode:
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.c398
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);
-}