icE1usb fw: Import I2C peripheral driver

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Change-Id: Ib729bb5f4e94eec25c86517042cdfdcb6847ba25
This commit is contained in:
Sylvain Munaut 2022-09-01 17:54:29 +02:00
parent b722de7a2a
commit 652c732ec4
3 changed files with 149 additions and 0 deletions

View File

@ -55,6 +55,7 @@ HEADERS_app=\
gps.h \
gpsdo.h \
ice1usb_proto.h \
i2c.h \
misc.h \
usb_desc_ids.h \
usb_dev.h \
@ -69,6 +70,7 @@ SOURCES_app=\
fw_app.c \
gps.c \
gpsdo.c \
i2c.c \
misc.c \
usb_desc_app.c \
usb_dev.c \

View File

@ -0,0 +1,125 @@
/*
* i2c.c
*
* Copyright (C) 2021-2022 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <stdint.h>
#include <stdbool.h>
#include "console.h"
#include "config.h"
struct i2c {
uint32_t csr;
} __attribute__((packed,aligned(4)));
#define I2C_CMD_START (0 << 12)
#define I2C_CMD_STOP (1 << 12)
#define I2C_CMD_WRITE (2 << 12)
#define I2C_CMD_READ (3 << 12)
#define I2C_GET_RESP (1 << 15)
#define I2C_ACK (0 << 8) /* ack bit value = 0 means ACK */
#define I2C_NAK (1 << 8) /* ack bit value = 1 means NAK */
#define I2C_VALID (1 << 31)
static volatile struct i2c * const i2c_regs = (void *)(I2C_BASE);
static inline uint32_t
_i2c_wait(void)
{
uint32_t v;
do {
v = i2c_regs->csr;
} while (!(v & I2C_VALID));
return v & 0x1ff;
}
bool
i2c_ready(void)
{
return i2c_regs->csr & (1 << 31);
}
void
i2c_start(void)
{
i2c_regs->csr = I2C_CMD_START;
}
void
i2c_stop(void)
{
i2c_regs->csr = I2C_CMD_STOP;
}
bool
i2c_write(uint8_t data)
{
i2c_regs->csr = I2C_CMD_WRITE | data;
return (_i2c_wait() & (I2C_ACK | I2C_NAK)) == I2C_ACK;
}
uint8_t
i2c_read(bool ack)
{
i2c_regs->csr = I2C_CMD_READ | I2C_GET_RESP | (ack ? I2C_ACK : I2C_NAK);
return _i2c_wait() & 0xff;
}
bool
i2c_write_reg(uint8_t dev, uint8_t reg, uint8_t val)
{
bool rv = true;
i2c_start();
rv = rv && i2c_write(dev);
rv = rv && i2c_write(reg);
rv = rv && i2c_write(val);
i2c_stop();
return rv;
}
bool
i2c_read_reg(uint8_t dev, uint8_t reg, uint8_t *val)
{
bool rv = true;
i2c_start();
rv = rv && i2c_write(dev);
rv = rv && i2c_write(reg);
if (rv)
i2c_start();
rv = rv && i2c_write(dev|1);
*val = rv ? i2c_read(false) : 0x00; // NAK
i2c_stop();
return rv;
}
bool
i2c_probe(uint8_t dev)
{
bool rv;
i2c_start();
rv = i2c_write(dev);
i2c_stop();
return rv;
}
void
i2c_scan(void)
{
for (uint8_t addr=0; addr<128; addr++) {
if (i2c_probe(addr << 1))
printf("I2C @ %08x\n", addr << 1);
}
}

View File

@ -0,0 +1,22 @@
/*
* i2c.h
*
* Copyright (C) 2021-2022 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
void i2c_start(void);
void i2c_stop(void);
bool i2c_write(uint8_t data);
uint8_t i2c_read(bool ack);
bool i2c_write_reg(uint8_t dev, uint8_t reg, uint8_t val);
bool i2c_read_reg (uint8_t dev, uint8_t reg, uint8_t *val);
bool i2c_probe(uint8_t dev);
void i2c_scan(void);