summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/soc/i2c.c
blob: 553a9bf8affa45ad37b1090b36bdaddc1e2e83d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <stdlib.h>
#include <stdint.h>

#include "encoding.h"
#include "platform.h"
#include "prci_driver.h"

#include "eos.h"
#include "i2s.h"
#include "i2c.h"

int eos_i2c_init(uint8_t wakeup_cause) {
    eos_i2c_speed(EOS_I2C_SPEED);
    eos_i2c_enable();

    return EOS_OK;
}

void eos_i2c_enable(void) {
    I2C0_REGB(I2C_CONTROL)  |=  I2C_CONTROL_EN;

    GPIO_REG(GPIO_IOF_SEL)  &= ~IOF0_I2C0_MASK;
    GPIO_REG(GPIO_IOF_EN)   |=  IOF0_I2C0_MASK;
}

void eos_i2c_disable(void) {
    GPIO_REG(GPIO_IOF_EN)   &= ~IOF0_I2C0_MASK;

    I2C0_REGB(I2C_CONTROL)  &= ~I2C_CONTROL_EN;
}

int eos_i2c_enabled(void) {
    return !!(GPIO_REG(GPIO_IOF_EN) & IOF0_I2C0_MASK);
}

void eos_i2c_speed(uint32_t baud_rate) {
    unsigned long clock_rate = PRCI_get_cpu_freq();
    uint16_t prescaler = (clock_rate / (baud_rate * 5)) - 1;

    I2C0_REGB(I2C_PRESCALE_LOW) = prescaler & 0xFF;
    I2C0_REGB(I2C_PRESCALE_HIGH) = (prescaler >> 8) & 0xFF;
}


static int i2c_read(uint8_t cmd) {
    I2C0_REGB(I2C_COMMAND) = I2C_CMD_READ | cmd;
    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);

    return I2C0_REGB(I2C_RECEIVE);
}

static int i2c_write(uint8_t cmd, uint8_t b) {
    I2C0_REGB(I2C_TRANSMIT) = b;
    I2C0_REGB(I2C_COMMAND) = I2C_CMD_WRITE | cmd;
    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);

    if (I2C0_REGB(I2C_STATUS) & I2C_STATUS_RXACK) return EOS_ERR;
    return EOS_OK;
}

static int i2c_addr(uint8_t addr, uint8_t rw_flag) {
    return i2c_write(I2C_CMD_START, ((addr & 0x7F) << 1) | (rw_flag & 0x1));
}

int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
    int rv;
    int i;

    rv = i2c_addr(addr, I2C_WRITE);
    if (rv) return rv;

    rv = i2c_write(0, reg);
    if (rv) return rv;

    rv = i2c_addr(addr, I2C_READ);
    if (rv) return rv;

    for (i=0; i<len; i++) {
        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
        if (rv < 0) return rv;

        buffer[i] = (uint8_t)rv;
    }

    return EOS_OK;
}

int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
    int rv;
    int i;

    rv = i2c_addr(addr, I2C_WRITE);
    if (rv) return rv;

    rv = i2c_write(0, reg >> 8);
    if (rv) return rv;

    rv = i2c_write(0, reg & 0xff);
    if (rv) return rv;

    rv = i2c_addr(addr, I2C_READ);
    if (rv) return rv;

    for (i=0; i<len; i++) {
        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
        if (rv < 0) return rv;

        buffer[i] = (uint8_t)rv;
    }

    return EOS_OK;
}

int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
    int rv;
    int i;

    rv = i2c_addr(addr, I2C_WRITE);
    if (rv) return rv;

    rv = i2c_write(0, reg);
    if (rv) return rv;

    for (i=0; i<len; i++) {
        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
        if (rv) return rv;
    }

    return EOS_OK;
}

int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
    int rv;
    int i;

    rv = i2c_addr(addr, I2C_WRITE);
    if (rv) return rv;

    rv = i2c_write(0, reg >> 8);
    if (rv) return rv;

    rv = i2c_write(0, reg & 0xff);
    if (rv) return rv;

    for (i=0; i<len; i++) {
        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
        if (rv) return rv;
    }

    return EOS_OK;
}