// SPDX-License-Identifier: GPL-2.0+ /* */ #include #include #include #include #include #include #include #include #include #include #define REG_BSR 0x0 #define REG_BCR 0x4 #define REG_CCR 0x8 #define REG_ADR 0xc #define REG_DAR 0x10 #define REG_CSR 0x14 #define REG_FSR 0x18 #define REG_BC2R 0x1c /* I2C register bit definitions */ #define BSR_FBT BIT(0) // First Byte Transfer #define BSR_GCA BIT(1) // General Call Address #define BSR_AAS BIT(2) // Address as Slave #define BSR_TRX BIT(3) // Transfer/Receive #define BSR_LRB BIT(4) // Last Received Bit #define BSR_AL BIT(5) // Arbitration Lost #define BSR_RSC BIT(6) // Repeated Start Cond. #define BSR_BB BIT(7) // Bus Busy #define BCR_INT BIT(0) // Interrupt #define BCR_INTE BIT(1) // Interrupt Enable #define BCR_GCAA BIT(2) // Gen. Call Access Ack. #define BCR_ACK BIT(3) // Acknowledge #define BCR_MSS BIT(4) // Master Slave Select #define BCR_SCC BIT(5) // Start Condition Cont. #define BCR_BEIE BIT(6) // Bus Error Int Enable #define BCR_BER BIT(7) // Bus Error #define CCR_CS_MASK (0x1f) // CCR Clock Period Sel. #define CCR_EN BIT(5) // Enable #define CCR_FM BIT(6) // Speed Mode Select #define CSR_CS_MASK (0x3f) // CSR Clock Period Sel. #define BC2R_SCLL BIT(0) // SCL Low Drive #define BC2R_SDAL BIT(1) // SDA Low Drive #define BC2R_SCLS BIT(4) // SCL Status #define BC2R_SDAS BIT(5) // SDA Status /* PCLK frequency */ #define BUS_CLK_FR(rate) (((rate) / 20000000) + 1) #define I2C_CLK_DEF 62500000 /* STANDARD MODE frequency */ #define CLK_MASTER_STD(rate) \ DIV_ROUND_UP(DIV_ROUND_UP((rate), I2C_SPEED_STANDARD_RATE) - 2, 2) /* FAST MODE frequency */ #define CLK_MASTER_FAST(rate) \ DIV_ROUND_UP((DIV_ROUND_UP((rate), I2C_SPEED_FAST_RATE) - 2) * 2, 3) /* (clkrate <= 18000000) */ /* calculate the value of CS bits in CCR register on standard mode */ #define CCR_CS_STD_MAX_18M(rate) \ ((CLK_MASTER_STD(rate) - 65) \ & CCR_CS_MASK) /* calculate the value of CS bits in CSR register on standard mode */ #define CSR_CS_STD_MAX_18M(rate) 0x00 /* calculate the value of CS bits in CCR register on fast mode */ #define CCR_CS_FAST_MAX_18M(rate) \ ((CLK_MASTER_FAST(rate) - 1) \ & CCR_CS_MASK) /* calculate the value of CS bits in CSR register on fast mode */ #define CSR_CS_FAST_MAX_18M(rate) 0x00 /* (clkrate > 18000000) */ /* calculate the value of CS bits in CCR register on standard mode */ #define CCR_CS_STD_MIN_18M(rate) \ ((CLK_MASTER_STD(rate) - 1) \ & CCR_CS_MASK) /* calculate the value of CS bits in CSR register on standard mode */ #define CSR_CS_STD_MIN_18M(rate) \ (((CLK_MASTER_STD(rate) - 1) >> 5) \ & CSR_CS_MASK) /* calculate the value of CS bits in CCR register on fast mode */ #define CCR_CS_FAST_MIN_18M(rate) \ ((CLK_MASTER_FAST(rate) - 1) \ & CCR_CS_MASK) /* calculate the value of CS bits in CSR register on fast mode */ #define CSR_CS_FAST_MIN_18M(rate) \ (((CLK_MASTER_FAST(rate) - 1) >> 5) \ & CSR_CS_MASK) /* min I2C clock frequency 14M */ #define MIN_CLK_RATE (14 * 1000000) /* max I2C clock frequency 200M */ #define MAX_CLK_RATE (200 * 1000000) /* I2C clock frequency 18M */ #define CLK_RATE_18M (18 * 1000000) #define SPEED_FM 400 // Fast Mode #define SPEED_SM 100 // Standard Mode DECLARE_GLOBAL_DATA_PTR; struct synquacer_i2c { void __iomem *base; unsigned long pclkrate; unsigned long speed_khz; }; static int wait_irq(struct udevice *dev) { struct synquacer_i2c *i2c = dev_get_priv(dev); int timeout = 500000; do { if (readb(i2c->base + REG_BCR) & BCR_INT) return 0; } while (timeout--); pr_err("%s: timeout\n", __func__); return -1; } static int synquacer_i2c_xfer_start(struct synquacer_i2c *i2c, int addr, int read) { u8 bsr, bcr; writeb((addr << 1) | (read ? 1 : 0), i2c->base + REG_DAR); bsr = readb(i2c->base + REG_BSR); bcr = readb(i2c->base + REG_BCR); if ((bsr & BSR_BB) && !(bcr & BCR_MSS)) return -EBUSY; if (bsr & BSR_BB) { writeb(bcr | BCR_SCC, i2c->base + REG_BCR); } else { if (bcr & BCR_MSS) return -EAGAIN; /* Start Condition + Enable Interrupts */ writeb(bcr | BCR_MSS | BCR_INTE | BCR_BEIE, i2c->base + REG_BCR); } udelay(100); return 0; } static int synquacer_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) { struct synquacer_i2c *i2c = dev_get_priv(bus); u8 bsr, bcr; int idx; for (; nmsgs > 0; nmsgs--, msg++) { synquacer_i2c_xfer_start(i2c, msg->addr, msg->flags & I2C_M_RD); if (wait_irq(bus)) return -EREMOTEIO; bsr = readb(i2c->base + REG_BSR); if (bsr & BSR_LRB) { debug("%s: No ack received\n", __func__); return -EREMOTEIO; } idx = 0; do { bsr = readb(i2c->base + REG_BSR); bcr = readb(i2c->base + REG_BCR); if (bcr & BCR_BER) { debug("%s: Bus error detected\n", __func__); return -EREMOTEIO; } if ((bsr & BSR_AL) || !(bcr & BCR_MSS)) { debug("%s: Arbitration lost\n", __func__); return -EREMOTEIO; } if (msg->flags & I2C_M_RD) { bcr = BCR_MSS | BCR_INTE | BCR_BEIE; if (idx < msg->len - 1) bcr |= BCR_ACK; writeb(bcr, i2c->base + REG_BCR); if (wait_irq(bus)) return -EREMOTEIO; bsr = readb(i2c->base + REG_BSR); if (!(bsr & BSR_FBT)) msg->buf[idx++] = readb(i2c->base + REG_DAR); } else { writeb(msg->buf[idx++], i2c->base + REG_DAR); bcr = BCR_MSS | BCR_INTE | BCR_BEIE; writeb(bcr, i2c->base + REG_BCR); if (wait_irq(bus)) return -EREMOTEIO; bsr = readb(i2c->base + REG_BSR); if (bsr & BSR_LRB) { debug("%s: no ack\n", __func__); return -EREMOTEIO; } } } while (idx < msg->len); } /* Force bus state to idle, terminating any ongoing transfer */ writeb(0, i2c->base + REG_BCR); udelay(100); return 0; } static void synquacer_i2c_hw_reset(struct synquacer_i2c *i2c) { /* Disable clock */ writeb(0, i2c->base + REG_CCR); writeb(0, i2c->base + REG_CSR); /* Set own Address */ writeb(0, i2c->base + REG_ADR); /* Set PCLK frequency */ writeb(BUS_CLK_FR(i2c->pclkrate), i2c->base + REG_FSR); /* clear IRQ (INT=0, BER=0), Interrupt Disable */ writeb(0, i2c->base + REG_BCR); writeb(0, i2c->base + REG_BC2R); } static int synquacer_i2c_get_bus_speed(struct udevice *bus) { struct synquacer_i2c *i2c = dev_get_priv(bus); return i2c->speed_khz * 1000; } static int synquacer_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct synquacer_i2c *i2c = dev_get_priv(bus); u32 rt = i2c->pclkrate; u8 ccr_cs, csr_cs; /* Set PCLK frequency */ writeb(BUS_CLK_FR(i2c->pclkrate), i2c->base + REG_FSR); if (speed >= SPEED_FM * 1000) { i2c->speed_khz = SPEED_FM; if (i2c->pclkrate <= CLK_RATE_18M) { ccr_cs = CCR_CS_FAST_MAX_18M(rt); csr_cs = CSR_CS_FAST_MAX_18M(rt); } else { ccr_cs = CCR_CS_FAST_MIN_18M(rt); csr_cs = CSR_CS_FAST_MIN_18M(rt); } /* Set Clock and enable, Set fast mode */ writeb(ccr_cs | CCR_FM | CCR_EN, i2c->base + REG_CCR); writeb(csr_cs, i2c->base + REG_CSR); } else { i2c->speed_khz = SPEED_SM; if (i2c->pclkrate <= CLK_RATE_18M) { ccr_cs = CCR_CS_STD_MAX_18M(rt); csr_cs = CSR_CS_STD_MAX_18M(rt); } else { ccr_cs = CCR_CS_STD_MIN_18M(rt); csr_cs = CSR_CS_STD_MIN_18M(rt); } /* Set Clock and enable, Set standard mode */ writeb(ccr_cs | CCR_EN, i2c->base + REG_CCR); writeb(csr_cs, i2c->base + REG_CSR); } return 0; } static int synquacer_i2c_of_to_plat(struct udevice *bus) { struct synquacer_i2c *priv = dev_get_priv(bus); struct clk ck; int ret; ret = clk_get_by_index(bus, 0, &ck); if (ret < 0) { priv->pclkrate = I2C_CLK_DEF; } else { clk_enable(&ck); priv->pclkrate = clk_get_rate(&ck); } return 0; } static int synquacer_i2c_probe(struct udevice *bus) { struct synquacer_i2c *i2c = dev_get_priv(bus); i2c->base = dev_read_addr_ptr(bus); synquacer_i2c_hw_reset(i2c); synquacer_i2c_set_bus_speed(bus, 400000); /* set default speed */ return 0; } static const struct dm_i2c_ops synquacer_i2c_ops = { .xfer = synquacer_i2c_xfer, .set_bus_speed = synquacer_i2c_set_bus_speed, .get_bus_speed = synquacer_i2c_get_bus_speed, }; static const struct udevice_id synquacer_i2c_ids[] = { { .compatible = "socionext,synquacer-i2c", }, { } }; U_BOOT_DRIVER(sni_synquacer_i2c) = { .name = "sni_synquacer_i2c", .id = UCLASS_I2C, .of_match = synquacer_i2c_ids, .of_to_plat = synquacer_i2c_of_to_plat, .probe = synquacer_i2c_probe, .priv_auto = sizeof(struct synquacer_i2c), .ops = &synquacer_i2c_ops, };