#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: shark_iic.c,v 1.3 2025/09/15 13:23:02 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/ofw/openfirm.h>
#include <shark/shark/sequoia.h>
#include <dev/i2c/i2cvar.h>
#include <dev/i2c/i2c_bitbang.h>
#include <arm/cpufunc.h>
#define SEQUOIA_1GPIO PMC_GPCR_REG
#define SEQUOIA_2GPIO SEQ2_OGPIOCR_REG
#define IIC_CLK FOMPCR_M_PCON9
#define IIC_DATA_IN_DIR GPCR_M_GPIODIR3
#define IIC_DATA_IN GPCR_M_GPIODATA3
#define IIC_DATA_OUT_DIR GPIOCR2_M_GPIOBDIR1
#define SHARK_IIC_BIT_SDA 0x01
#define SHARK_IIC_BIT_SCL 0x02
#define SHARK_IIC_BIT_OUTPUT 0x04
#define SHARK_IIC_BIT_INPUT 0x08
struct sharkiic_softc {
device_t sc_dev;
struct i2c_controller sc_i2c;
};
static void
sequoiaBBInit(void)
{
uint16_t seqReg;
sequoiaLock();
sequoiaRead(SEQR_SEQPSR3_REG, &seqReg);
CLR(seqReg, SEQPSR3_M_PC9PINEN);
sequoiaWrite(SEQR_SEQPSR3_REG, seqReg);
sequoiaRead(PMC_FOMPCR_REG, &seqReg);
SET(seqReg, IIC_CLK);
sequoiaWrite(PMC_FOMPCR_REG, seqReg);
sequoiaRead(PMC_GPIOCR2_REG, &seqReg);
SET(seqReg, IIC_DATA_OUT_DIR);
sequoiaWrite(PMC_GPIOCR2_REG, seqReg);
sequoiaRead(SEQR_SEQPSR2_REG, &seqReg);
SET(seqReg, SEQPSR2_M_GPIOB1PINEN);
sequoiaWrite(SEQR_SEQPSR2_REG, seqReg);
sequoiaRead(SEQ2_SEQ2PSR_REG, &seqReg);
CLR(seqReg, SEQ2PSR_M_GPIOPINEN);
sequoiaWrite(SEQ2_SEQ2PSR_REG, seqReg);
sequoiaRead(SEQUOIA_1GPIO, &seqReg);
CLR(seqReg, IIC_DATA_IN_DIR);
sequoiaWrite(SEQUOIA_1GPIO, seqReg);
sequoiaUnlock();
}
static void
sequoiaBBSetBits(uint32_t bits)
{
uint16_t seqRegSDA, seqRegSCL;
sequoiaLock();
sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL);
sequoiaRead(SEQR_SEQPSR2_REG, &seqRegSDA);
if (bits & SHARK_IIC_BIT_SCL) {
CLR(seqRegSCL, IIC_CLK);
} else {
SET(seqRegSCL, IIC_CLK);
}
if (bits & SHARK_IIC_BIT_SDA) {
CLR(seqRegSDA, SEQPSR2_M_GPIOB1PINEN);
} else {
SET(seqRegSDA, SEQPSR2_M_GPIOB1PINEN);
}
sequoiaWrite(PMC_FOMPCR_REG, seqRegSCL);
sequoiaWrite(SEQR_SEQPSR2_REG, seqRegSDA);
sequoiaUnlock();
}
static void
sequoiaBBSetDir(uint32_t dir)
{
uint16_t seqReg;
sequoiaLock();
sequoiaRead(PMC_GPIOCR2_REG, &seqReg);
if (dir & SHARK_IIC_BIT_OUTPUT)
SET(seqReg, IIC_DATA_OUT_DIR);
else
CLR(seqReg, IIC_DATA_OUT_DIR);
sequoiaWrite(PMC_GPIOCR2_REG, seqReg);
sequoiaUnlock();
}
static uint32_t
sequoiaBBRead(void)
{
uint16_t seqRegSDA, seqRegSCL;
uint32_t bits = 0;
sequoiaLock();
sequoiaRead(SEQUOIA_1GPIO, &seqRegSDA);
sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL);
sequoiaUnlock();
if (ISSET(seqRegSDA, IIC_DATA_IN))
bits |= SHARK_IIC_BIT_SDA;
if (!ISSET(seqRegSCL, IIC_CLK))
bits |= SHARK_IIC_BIT_SCL;
return bits;
}
static void
sharkiicbb_set_bits(void *cookie, uint32_t bits)
{
sequoiaBBSetBits(bits);
}
static void
sharkiicbb_set_dir(void *cookie, uint32_t dir)
{
sequoiaBBSetDir(dir);
}
static uint32_t
sharkiicbb_read(void *cookie)
{
return sequoiaBBRead();
}
static const struct i2c_bitbang_ops sharkiicbb_ops = {
.ibo_set_bits = sharkiicbb_set_bits,
.ibo_set_dir = sharkiicbb_set_dir,
.ibo_read_bits = sharkiicbb_read,
.ibo_bits = {
[I2C_BIT_SDA] = SHARK_IIC_BIT_SDA,
[I2C_BIT_SCL] = SHARK_IIC_BIT_SCL,
[I2C_BIT_OUTPUT] = SHARK_IIC_BIT_OUTPUT,
[I2C_BIT_INPUT] = SHARK_IIC_BIT_INPUT,
},
};
static int
sharkiic_send_start(void *cookie, int flags)
{
return (i2c_bitbang_send_start(cookie, flags, &sharkiicbb_ops));
}
static int
sharkiic_send_stop(void *cookie, int flags)
{
return (i2c_bitbang_send_stop(cookie, flags, &sharkiicbb_ops));
}
static int
sharkiic_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
{
return (i2c_bitbang_initiate_xfer(cookie, addr, flags,
&sharkiicbb_ops));
}
static int
sharkiic_read_byte(void *cookie, uint8_t *valp, int flags)
{
return (i2c_bitbang_read_byte(cookie, valp, flags, &sharkiicbb_ops));
}
static int
sharkiic_write_byte(void *cookie, uint8_t val, int flags)
{
return (i2c_bitbang_write_byte(cookie, val, flags, &sharkiicbb_ops));
}
static int
sharkiic_match(device_t parent, cfdata_t match, void *aux)
{
struct ofbus_attach_args *oba = aux;
return strcmp(oba->oba_ofname, "dec,dnard-i2c") == 0;
}
static void
sharkiic_attach(device_t parent, device_t self, void *aux)
{
struct sharkiic_softc *sc = device_private(self);
aprint_naive("\n");
aprint_normal("\n");
sequoiaBBInit();
iic_tag_init(&sc->sc_i2c);
sc->sc_i2c.ic_cookie = sc;
sc->sc_i2c.ic_send_start = sharkiic_send_start;
sc->sc_i2c.ic_send_stop = sharkiic_send_stop;
sc->sc_i2c.ic_initiate_xfer = sharkiic_initiate_xfer;
sc->sc_i2c.ic_read_byte = sharkiic_read_byte;
sc->sc_i2c.ic_write_byte = sharkiic_write_byte;
iicbus_attach(self, &sc->sc_i2c);
}
CFATTACH_DECL_NEW(sharkiic, sizeof(struct sharkiic_softc),
sharkiic_match, sharkiic_attach, NULL, NULL);