18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * i2c-ocores.c: I2C bus driver for OpenCores I2C controller 48c2ecf20Sopenharmony_ci * (https://opencores.org/project/i2c/overview) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Peter Korsgaard <peter@korsgaard.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Support for the GRLIB port of the controller by 98c2ecf20Sopenharmony_ci * Andreas Larsson <andreas@gaisler.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/errno.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/i2c.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/wait.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_data/i2c-ocores.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci#include <linux/log2.h> 268c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 278c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * 'process_lock' exists because ocores_process() and ocores_process_timeout() 318c2ecf20Sopenharmony_ci * can't run in parallel. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_cistruct ocores_i2c { 348c2ecf20Sopenharmony_ci void __iomem *base; 358c2ecf20Sopenharmony_ci int iobase; 368c2ecf20Sopenharmony_ci u32 reg_shift; 378c2ecf20Sopenharmony_ci u32 reg_io_width; 388c2ecf20Sopenharmony_ci unsigned long flags; 398c2ecf20Sopenharmony_ci wait_queue_head_t wait; 408c2ecf20Sopenharmony_ci struct i2c_adapter adap; 418c2ecf20Sopenharmony_ci struct i2c_msg *msg; 428c2ecf20Sopenharmony_ci int pos; 438c2ecf20Sopenharmony_ci int nmsgs; 448c2ecf20Sopenharmony_ci int state; /* see STATE_ */ 458c2ecf20Sopenharmony_ci spinlock_t process_lock; 468c2ecf20Sopenharmony_ci struct clk *clk; 478c2ecf20Sopenharmony_ci int ip_clock_khz; 488c2ecf20Sopenharmony_ci int bus_clock_khz; 498c2ecf20Sopenharmony_ci void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); 508c2ecf20Sopenharmony_ci u8 (*getreg)(struct ocores_i2c *i2c, int reg); 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* registers */ 548c2ecf20Sopenharmony_ci#define OCI2C_PRELOW 0 558c2ecf20Sopenharmony_ci#define OCI2C_PREHIGH 1 568c2ecf20Sopenharmony_ci#define OCI2C_CONTROL 2 578c2ecf20Sopenharmony_ci#define OCI2C_DATA 3 588c2ecf20Sopenharmony_ci#define OCI2C_CMD 4 /* write only */ 598c2ecf20Sopenharmony_ci#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define OCI2C_CTRL_IEN 0x40 628c2ecf20Sopenharmony_ci#define OCI2C_CTRL_EN 0x80 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define OCI2C_CMD_START 0x91 658c2ecf20Sopenharmony_ci#define OCI2C_CMD_STOP 0x41 668c2ecf20Sopenharmony_ci#define OCI2C_CMD_READ 0x21 678c2ecf20Sopenharmony_ci#define OCI2C_CMD_WRITE 0x11 688c2ecf20Sopenharmony_ci#define OCI2C_CMD_READ_ACK 0x21 698c2ecf20Sopenharmony_ci#define OCI2C_CMD_READ_NACK 0x29 708c2ecf20Sopenharmony_ci#define OCI2C_CMD_IACK 0x01 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define OCI2C_STAT_IF 0x01 738c2ecf20Sopenharmony_ci#define OCI2C_STAT_TIP 0x02 748c2ecf20Sopenharmony_ci#define OCI2C_STAT_ARBLOST 0x20 758c2ecf20Sopenharmony_ci#define OCI2C_STAT_BUSY 0x40 768c2ecf20Sopenharmony_ci#define OCI2C_STAT_NACK 0x80 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define STATE_DONE 0 798c2ecf20Sopenharmony_ci#define STATE_START 1 808c2ecf20Sopenharmony_ci#define STATE_WRITE 2 818c2ecf20Sopenharmony_ci#define STATE_READ 3 828c2ecf20Sopenharmony_ci#define STATE_ERROR 4 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define TYPE_OCORES 0 858c2ecf20Sopenharmony_ci#define TYPE_GRLIB 1 868c2ecf20Sopenharmony_ci#define TYPE_SIFIVE_REV0 2 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci iowrite8(value, i2c->base + (reg << i2c->reg_shift)); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci iowrite16(value, i2c->base + (reg << i2c->reg_shift)); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci iowrite32(value, i2c->base + (reg << i2c->reg_shift)); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return ioread8(i2c->base + (reg << i2c->reg_shift)); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return ioread16(i2c->base + (reg << i2c->reg_shift)); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return ioread32(i2c->base + (reg << i2c->reg_shift)); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return ioread16be(i2c->base + (reg << i2c->reg_shift)); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return ioread32be(i2c->base + (reg << i2c->reg_shift)); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci outb(value, i2c->iobase + reg); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return inb(i2c->iobase + reg); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci i2c->setreg(i2c, reg, value); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return i2c->getreg(i2c, reg); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void ocores_process(struct ocores_i2c *i2c, u8 stat) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct i2c_msg *msg = i2c->msg; 1638c2ecf20Sopenharmony_ci unsigned long flags; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * If we spin here is because we are in timeout, so we are going 1678c2ecf20Sopenharmony_ci * to be in STATE_ERROR. See ocores_process_timeout() 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->process_lock, flags); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { 1728c2ecf20Sopenharmony_ci /* stop has been sent */ 1738c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); 1748c2ecf20Sopenharmony_ci wake_up(&i2c->wait); 1758c2ecf20Sopenharmony_ci goto out; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* error? */ 1798c2ecf20Sopenharmony_ci if (stat & OCI2C_STAT_ARBLOST) { 1808c2ecf20Sopenharmony_ci i2c->state = STATE_ERROR; 1818c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 1828c2ecf20Sopenharmony_ci goto out; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { 1868c2ecf20Sopenharmony_ci i2c->state = 1878c2ecf20Sopenharmony_ci (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (stat & OCI2C_STAT_NACK) { 1908c2ecf20Sopenharmony_ci i2c->state = STATE_ERROR; 1918c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 1928c2ecf20Sopenharmony_ci goto out; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } else { 1958c2ecf20Sopenharmony_ci msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* end of msg? */ 1998c2ecf20Sopenharmony_ci if (i2c->pos == msg->len) { 2008c2ecf20Sopenharmony_ci i2c->nmsgs--; 2018c2ecf20Sopenharmony_ci i2c->msg++; 2028c2ecf20Sopenharmony_ci i2c->pos = 0; 2038c2ecf20Sopenharmony_ci msg = i2c->msg; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (i2c->nmsgs) { /* end? */ 2068c2ecf20Sopenharmony_ci /* send start? */ 2078c2ecf20Sopenharmony_ci if (!(msg->flags & I2C_M_NOSTART)) { 2088c2ecf20Sopenharmony_ci u8 addr = i2c_8bit_addr_from_msg(msg); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci i2c->state = STATE_START; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_DATA, addr); 2138c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci i2c->state = (msg->flags & I2C_M_RD) 2178c2ecf20Sopenharmony_ci ? STATE_READ : STATE_WRITE; 2188c2ecf20Sopenharmony_ci } else { 2198c2ecf20Sopenharmony_ci i2c->state = STATE_DONE; 2208c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 2218c2ecf20Sopenharmony_ci goto out; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (i2c->state == STATE_READ) { 2268c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? 2278c2ecf20Sopenharmony_ci OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); 2288c2ecf20Sopenharmony_ci } else { 2298c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); 2308c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciout: 2348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->process_lock, flags); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic irqreturn_t ocores_isr(int irq, void *dev_id) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct ocores_i2c *i2c = dev_id; 2408c2ecf20Sopenharmony_ci u8 stat = oc_getreg(i2c, OCI2C_STATUS); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) { 2438c2ecf20Sopenharmony_ci if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY)) 2448c2ecf20Sopenharmony_ci return IRQ_NONE; 2458c2ecf20Sopenharmony_ci } else if (!(stat & OCI2C_STAT_IF)) { 2468c2ecf20Sopenharmony_ci return IRQ_NONE; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci ocores_process(i2c, stat); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/** 2548c2ecf20Sopenharmony_ci * Process timeout event 2558c2ecf20Sopenharmony_ci * @i2c: ocores I2C device instance 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic void ocores_process_timeout(struct ocores_i2c *i2c) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci unsigned long flags; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci spin_lock_irqsave(&i2c->process_lock, flags); 2628c2ecf20Sopenharmony_ci i2c->state = STATE_ERROR; 2638c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 2648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i2c->process_lock, flags); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/** 2688c2ecf20Sopenharmony_ci * Wait until something change in a given register 2698c2ecf20Sopenharmony_ci * @i2c: ocores I2C device instance 2708c2ecf20Sopenharmony_ci * @reg: register to query 2718c2ecf20Sopenharmony_ci * @mask: bitmask to apply on register value 2728c2ecf20Sopenharmony_ci * @val: expected result 2738c2ecf20Sopenharmony_ci * @timeout: timeout in jiffies 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Timeout is necessary to avoid to stay here forever when the chip 2768c2ecf20Sopenharmony_ci * does not answer correctly. 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * Return: 0 on success, -ETIMEDOUT on timeout 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_cistatic int ocores_wait(struct ocores_i2c *i2c, 2818c2ecf20Sopenharmony_ci int reg, u8 mask, u8 val, 2828c2ecf20Sopenharmony_ci const unsigned long timeout) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci unsigned long j; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci j = jiffies + timeout; 2878c2ecf20Sopenharmony_ci while (1) { 2888c2ecf20Sopenharmony_ci u8 status = oc_getreg(i2c, reg); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if ((status & mask) == val) 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (time_after(jiffies, j)) 2948c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/** 3008c2ecf20Sopenharmony_ci * Wait until is possible to process some data 3018c2ecf20Sopenharmony_ci * @i2c: ocores I2C device instance 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * Used when the device is in polling mode (interrupts disabled). 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * Return: 0 on success, -ETIMEDOUT on timeout 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic int ocores_poll_wait(struct ocores_i2c *i2c) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci u8 mask; 3108c2ecf20Sopenharmony_ci int err; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { 3138c2ecf20Sopenharmony_ci /* transfer is over */ 3148c2ecf20Sopenharmony_ci mask = OCI2C_STAT_BUSY; 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci /* on going transfer */ 3178c2ecf20Sopenharmony_ci mask = OCI2C_STAT_TIP; 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * We wait for the data to be transferred (8bit), 3208c2ecf20Sopenharmony_ci * then we start polling on the ACK/NACK bit 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci udelay((8 * 1000) / i2c->bus_clock_khz); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* 3268c2ecf20Sopenharmony_ci * once we are here we expect to get the expected result immediately 3278c2ecf20Sopenharmony_ci * so if after 1ms we timeout then something is broken. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(1)); 3308c2ecf20Sopenharmony_ci if (err) 3318c2ecf20Sopenharmony_ci dev_warn(i2c->adap.dev.parent, 3328c2ecf20Sopenharmony_ci "%s: STATUS timeout, bit 0x%x did not clear in 1ms\n", 3338c2ecf20Sopenharmony_ci __func__, mask); 3348c2ecf20Sopenharmony_ci return err; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/** 3388c2ecf20Sopenharmony_ci * It handles an IRQ-less transfer 3398c2ecf20Sopenharmony_ci * @i2c: ocores I2C device instance 3408c2ecf20Sopenharmony_ci * 3418c2ecf20Sopenharmony_ci * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same 3428c2ecf20Sopenharmony_ci * (only that IRQ are not produced). This means that we can re-use entirely 3438c2ecf20Sopenharmony_ci * ocores_isr(), we just add our polling code around it. 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * It can run in atomic context 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Return: 0 on success, -ETIMEDOUT on timeout 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_cistatic int ocores_process_polling(struct ocores_i2c *i2c) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci irqreturn_t ret; 3528c2ecf20Sopenharmony_ci int err = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci while (1) { 3558c2ecf20Sopenharmony_ci err = ocores_poll_wait(i2c); 3568c2ecf20Sopenharmony_ci if (err) 3578c2ecf20Sopenharmony_ci break; /* timeout */ 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = ocores_isr(-1, i2c); 3608c2ecf20Sopenharmony_ci if (ret == IRQ_NONE) 3618c2ecf20Sopenharmony_ci break; /* all messages have been transferred */ 3628c2ecf20Sopenharmony_ci else { 3638c2ecf20Sopenharmony_ci if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) 3648c2ecf20Sopenharmony_ci if (i2c->state == STATE_DONE) 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return err; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int ocores_xfer_core(struct ocores_i2c *i2c, 3738c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num, 3748c2ecf20Sopenharmony_ci bool polling) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci int ret = 0; 3778c2ecf20Sopenharmony_ci u8 ctrl; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ctrl = oc_getreg(i2c, OCI2C_CONTROL); 3808c2ecf20Sopenharmony_ci if (polling) 3818c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); 3828c2ecf20Sopenharmony_ci else 3838c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci i2c->msg = msgs; 3868c2ecf20Sopenharmony_ci i2c->pos = 0; 3878c2ecf20Sopenharmony_ci i2c->nmsgs = num; 3888c2ecf20Sopenharmony_ci i2c->state = STATE_START; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); 3918c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (polling) { 3948c2ecf20Sopenharmony_ci ret = ocores_process_polling(i2c); 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci if (wait_event_timeout(i2c->wait, 3978c2ecf20Sopenharmony_ci (i2c->state == STATE_ERROR) || 3988c2ecf20Sopenharmony_ci (i2c->state == STATE_DONE), HZ) == 0) 3998c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci if (ret) { 4028c2ecf20Sopenharmony_ci ocores_process_timeout(i2c); 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return (i2c->state == STATE_DONE) ? num : -EIO; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int ocores_xfer_polling(struct i2c_adapter *adap, 4108c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int ocores_xfer(struct i2c_adapter *adap, 4168c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, false); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int ocores_init(struct device *dev, struct ocores_i2c *i2c) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci int prescale; 4248c2ecf20Sopenharmony_ci int diff; 4258c2ecf20Sopenharmony_ci u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* make sure the device is disabled */ 4288c2ecf20Sopenharmony_ci ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); 4298c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; 4328c2ecf20Sopenharmony_ci prescale = clamp(prescale, 0, 0xffff); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; 4358c2ecf20Sopenharmony_ci if (abs(diff) > i2c->bus_clock_khz / 10) { 4368c2ecf20Sopenharmony_ci dev_err(dev, 4378c2ecf20Sopenharmony_ci "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", 4388c2ecf20Sopenharmony_ci i2c->ip_clock_khz, i2c->bus_clock_khz); 4398c2ecf20Sopenharmony_ci return -EINVAL; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); 4438c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Init the device */ 4468c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); 4478c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic u32 ocores_func(struct i2c_adapter *adap) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic struct i2c_algorithm ocores_algorithm = { 4598c2ecf20Sopenharmony_ci .master_xfer = ocores_xfer, 4608c2ecf20Sopenharmony_ci .master_xfer_atomic = ocores_xfer_polling, 4618c2ecf20Sopenharmony_ci .functionality = ocores_func, 4628c2ecf20Sopenharmony_ci}; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic const struct i2c_adapter ocores_adapter = { 4658c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4668c2ecf20Sopenharmony_ci .name = "i2c-ocores", 4678c2ecf20Sopenharmony_ci .class = I2C_CLASS_DEPRECATED, 4688c2ecf20Sopenharmony_ci .algo = &ocores_algorithm, 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic const struct of_device_id ocores_i2c_match[] = { 4728c2ecf20Sopenharmony_ci { 4738c2ecf20Sopenharmony_ci .compatible = "opencores,i2c-ocores", 4748c2ecf20Sopenharmony_ci .data = (void *)TYPE_OCORES, 4758c2ecf20Sopenharmony_ci }, 4768c2ecf20Sopenharmony_ci { 4778c2ecf20Sopenharmony_ci .compatible = "aeroflexgaisler,i2cmst", 4788c2ecf20Sopenharmony_ci .data = (void *)TYPE_GRLIB, 4798c2ecf20Sopenharmony_ci }, 4808c2ecf20Sopenharmony_ci { 4818c2ecf20Sopenharmony_ci .compatible = "sifive,fu540-c000-i2c", 4828c2ecf20Sopenharmony_ci .data = (void *)TYPE_SIFIVE_REV0, 4838c2ecf20Sopenharmony_ci }, 4848c2ecf20Sopenharmony_ci { 4858c2ecf20Sopenharmony_ci .compatible = "sifive,i2c0", 4868c2ecf20Sopenharmony_ci .data = (void *)TYPE_SIFIVE_REV0, 4878c2ecf20Sopenharmony_ci }, 4888c2ecf20Sopenharmony_ci {}, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ocores_i2c_match); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 4938c2ecf20Sopenharmony_ci/* 4948c2ecf20Sopenharmony_ci * Read and write functions for the GRLIB port of the controller. Registers are 4958c2ecf20Sopenharmony_ci * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one 4968c2ecf20Sopenharmony_ci * register. The subsequent registers have their offsets decreased accordingly. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_cistatic u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci u32 rd; 5018c2ecf20Sopenharmony_ci int rreg = reg; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (reg != OCI2C_PRELOW) 5048c2ecf20Sopenharmony_ci rreg--; 5058c2ecf20Sopenharmony_ci rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); 5068c2ecf20Sopenharmony_ci if (reg == OCI2C_PREHIGH) 5078c2ecf20Sopenharmony_ci return (u8)(rd >> 8); 5088c2ecf20Sopenharmony_ci else 5098c2ecf20Sopenharmony_ci return (u8)rd; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci u32 curr, wr; 5158c2ecf20Sopenharmony_ci int rreg = reg; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (reg != OCI2C_PRELOW) 5188c2ecf20Sopenharmony_ci rreg--; 5198c2ecf20Sopenharmony_ci if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { 5208c2ecf20Sopenharmony_ci curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); 5218c2ecf20Sopenharmony_ci if (reg == OCI2C_PRELOW) 5228c2ecf20Sopenharmony_ci wr = (curr & 0xff00) | value; 5238c2ecf20Sopenharmony_ci else 5248c2ecf20Sopenharmony_ci wr = (((u32)value) << 8) | (curr & 0xff); 5258c2ecf20Sopenharmony_ci } else { 5268c2ecf20Sopenharmony_ci wr = value; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int ocores_i2c_of_probe(struct platform_device *pdev, 5328c2ecf20Sopenharmony_ci struct ocores_i2c *i2c) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 5358c2ecf20Sopenharmony_ci const struct of_device_id *match; 5368c2ecf20Sopenharmony_ci u32 val; 5378c2ecf20Sopenharmony_ci u32 clock_frequency; 5388c2ecf20Sopenharmony_ci bool clock_frequency_present; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { 5418c2ecf20Sopenharmony_ci /* no 'reg-shift', check for deprecated 'regstep' */ 5428c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "regstep", &val)) { 5438c2ecf20Sopenharmony_ci if (!is_power_of_2(val)) { 5448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid regstep %d\n", 5458c2ecf20Sopenharmony_ci val); 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci i2c->reg_shift = ilog2(val); 5498c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 5508c2ecf20Sopenharmony_ci "regstep property deprecated, use reg-shift\n"); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci clock_frequency_present = !of_property_read_u32(np, "clock-frequency", 5558c2ecf20Sopenharmony_ci &clock_frequency); 5568c2ecf20Sopenharmony_ci i2c->bus_clock_khz = 100; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, NULL); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!IS_ERR(i2c->clk)) { 5618c2ecf20Sopenharmony_ci int ret = clk_prepare_enable(i2c->clk); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (ret) { 5648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5658c2ecf20Sopenharmony_ci "clk_prepare_enable failed: %d\n", ret); 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; 5698c2ecf20Sopenharmony_ci if (clock_frequency_present) 5708c2ecf20Sopenharmony_ci i2c->bus_clock_khz = clock_frequency / 1000; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (i2c->ip_clock_khz == 0) { 5748c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "opencores,ip-clock-frequency", 5758c2ecf20Sopenharmony_ci &val)) { 5768c2ecf20Sopenharmony_ci if (!clock_frequency_present) { 5778c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5788c2ecf20Sopenharmony_ci "Missing required parameter 'opencores,ip-clock-frequency'\n"); 5798c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 5808c2ecf20Sopenharmony_ci return -ENODEV; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci i2c->ip_clock_khz = clock_frequency / 1000; 5838c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 5848c2ecf20Sopenharmony_ci "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); 5858c2ecf20Sopenharmony_ci } else { 5868c2ecf20Sopenharmony_ci i2c->ip_clock_khz = val / 1000; 5878c2ecf20Sopenharmony_ci if (clock_frequency_present) 5888c2ecf20Sopenharmony_ci i2c->bus_clock_khz = clock_frequency / 1000; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "reg-io-width", 5938c2ecf20Sopenharmony_ci &i2c->reg_io_width); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci match = of_match_node(ocores_i2c_match, pdev->dev.of_node); 5968c2ecf20Sopenharmony_ci if (match && (long)match->data == TYPE_GRLIB) { 5978c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); 5988c2ecf20Sopenharmony_ci i2c->setreg = oc_setreg_grlib; 5998c2ecf20Sopenharmony_ci i2c->getreg = oc_getreg_grlib; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci#else 6058c2ecf20Sopenharmony_ci#define ocores_i2c_of_probe(pdev, i2c) -ENODEV 6068c2ecf20Sopenharmony_ci#endif 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int ocores_i2c_probe(struct platform_device *pdev) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct ocores_i2c *i2c; 6118c2ecf20Sopenharmony_ci struct ocores_i2c_platform_data *pdata; 6128c2ecf20Sopenharmony_ci const struct of_device_id *match; 6138c2ecf20Sopenharmony_ci struct resource *res; 6148c2ecf20Sopenharmony_ci int irq; 6158c2ecf20Sopenharmony_ci int ret; 6168c2ecf20Sopenharmony_ci int i; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); 6198c2ecf20Sopenharmony_ci if (!i2c) 6208c2ecf20Sopenharmony_ci return -ENOMEM; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci spin_lock_init(&i2c->process_lock); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6258c2ecf20Sopenharmony_ci if (res) { 6268c2ecf20Sopenharmony_ci i2c->base = devm_ioremap_resource(&pdev->dev, res); 6278c2ecf20Sopenharmony_ci if (IS_ERR(i2c->base)) 6288c2ecf20Sopenharmony_ci return PTR_ERR(i2c->base); 6298c2ecf20Sopenharmony_ci } else { 6308c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IO, 0); 6318c2ecf20Sopenharmony_ci if (!res) 6328c2ecf20Sopenharmony_ci return -EINVAL; 6338c2ecf20Sopenharmony_ci i2c->iobase = res->start; 6348c2ecf20Sopenharmony_ci if (!devm_request_region(&pdev->dev, res->start, 6358c2ecf20Sopenharmony_ci resource_size(res), 6368c2ecf20Sopenharmony_ci pdev->name)) { 6378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't get I/O resource.\n"); 6388c2ecf20Sopenharmony_ci return -EBUSY; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci i2c->setreg = oc_setreg_io_8; 6418c2ecf20Sopenharmony_ci i2c->getreg = oc_getreg_io_8; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&pdev->dev); 6458c2ecf20Sopenharmony_ci if (pdata) { 6468c2ecf20Sopenharmony_ci i2c->reg_shift = pdata->reg_shift; 6478c2ecf20Sopenharmony_ci i2c->reg_io_width = pdata->reg_io_width; 6488c2ecf20Sopenharmony_ci i2c->ip_clock_khz = pdata->clock_khz; 6498c2ecf20Sopenharmony_ci if (pdata->bus_khz) 6508c2ecf20Sopenharmony_ci i2c->bus_clock_khz = pdata->bus_khz; 6518c2ecf20Sopenharmony_ci else 6528c2ecf20Sopenharmony_ci i2c->bus_clock_khz = 100; 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci ret = ocores_i2c_of_probe(pdev, i2c); 6558c2ecf20Sopenharmony_ci if (ret) 6568c2ecf20Sopenharmony_ci return ret; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (i2c->reg_io_width == 0) 6608c2ecf20Sopenharmony_ci i2c->reg_io_width = 1; /* Set to default value */ 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!i2c->setreg || !i2c->getreg) { 6638c2ecf20Sopenharmony_ci bool be = pdata ? pdata->big_endian : 6648c2ecf20Sopenharmony_ci of_device_is_big_endian(pdev->dev.of_node); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci switch (i2c->reg_io_width) { 6678c2ecf20Sopenharmony_ci case 1: 6688c2ecf20Sopenharmony_ci i2c->setreg = oc_setreg_8; 6698c2ecf20Sopenharmony_ci i2c->getreg = oc_getreg_8; 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci case 2: 6738c2ecf20Sopenharmony_ci i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; 6748c2ecf20Sopenharmony_ci i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci case 4: 6788c2ecf20Sopenharmony_ci i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; 6798c2ecf20Sopenharmony_ci i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", 6848c2ecf20Sopenharmony_ci i2c->reg_io_width); 6858c2ecf20Sopenharmony_ci ret = -EINVAL; 6868c2ecf20Sopenharmony_ci goto err_clk; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci init_waitqueue_head(&i2c->wait); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 6938c2ecf20Sopenharmony_ci if (irq == -ENXIO) { 6948c2ecf20Sopenharmony_ci ocores_algorithm.master_xfer = ocores_xfer_polling; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for 6988c2ecf20Sopenharmony_ci * FU540-C000 SoC in polling mode. 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci match = of_match_node(ocores_i2c_match, pdev->dev.of_node); 7018c2ecf20Sopenharmony_ci if (match && (long)match->data == TYPE_SIFIVE_REV0) 7028c2ecf20Sopenharmony_ci i2c->flags |= OCORES_FLAG_BROKEN_IRQ; 7038c2ecf20Sopenharmony_ci } else { 7048c2ecf20Sopenharmony_ci if (irq < 0) 7058c2ecf20Sopenharmony_ci return irq; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (ocores_algorithm.master_xfer != ocores_xfer_polling) { 7098c2ecf20Sopenharmony_ci ret = devm_request_any_context_irq(&pdev->dev, irq, 7108c2ecf20Sopenharmony_ci ocores_isr, 0, 7118c2ecf20Sopenharmony_ci pdev->name, i2c); 7128c2ecf20Sopenharmony_ci if (ret) { 7138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot claim IRQ\n"); 7148c2ecf20Sopenharmony_ci goto err_clk; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ret = ocores_init(&pdev->dev, i2c); 7198c2ecf20Sopenharmony_ci if (ret) 7208c2ecf20Sopenharmony_ci goto err_clk; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* hook up driver to tree */ 7238c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, i2c); 7248c2ecf20Sopenharmony_ci i2c->adap = ocores_adapter; 7258c2ecf20Sopenharmony_ci i2c_set_adapdata(&i2c->adap, i2c); 7268c2ecf20Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 7278c2ecf20Sopenharmony_ci i2c->adap.dev.of_node = pdev->dev.of_node; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* add i2c adapter to i2c tree */ 7308c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&i2c->adap); 7318c2ecf20Sopenharmony_ci if (ret) 7328c2ecf20Sopenharmony_ci goto err_clk; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* add in known devices to the bus */ 7358c2ecf20Sopenharmony_ci if (pdata) { 7368c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_devices; i++) 7378c2ecf20Sopenharmony_ci i2c_new_client_device(&i2c->adap, pdata->devices + i); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cierr_clk: 7438c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 7448c2ecf20Sopenharmony_ci return ret; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int ocores_i2c_remove(struct platform_device *pdev) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct ocores_i2c *i2c = platform_get_drvdata(pdev); 7508c2ecf20Sopenharmony_ci u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* disable i2c logic */ 7538c2ecf20Sopenharmony_ci ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); 7548c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* remove adapter & data */ 7578c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c->adap); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (!IS_ERR(i2c->clk)) 7608c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7668c2ecf20Sopenharmony_cistatic int ocores_i2c_suspend(struct device *dev) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct ocores_i2c *i2c = dev_get_drvdata(dev); 7698c2ecf20Sopenharmony_ci u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* make sure the device is disabled */ 7728c2ecf20Sopenharmony_ci ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); 7738c2ecf20Sopenharmony_ci oc_setreg(i2c, OCI2C_CONTROL, ctrl); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!IS_ERR(i2c->clk)) 7768c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic int ocores_i2c_resume(struct device *dev) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci struct ocores_i2c *i2c = dev_get_drvdata(dev); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (!IS_ERR(i2c->clk)) { 7858c2ecf20Sopenharmony_ci unsigned long rate; 7868c2ecf20Sopenharmony_ci int ret = clk_prepare_enable(i2c->clk); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (ret) { 7898c2ecf20Sopenharmony_ci dev_err(dev, 7908c2ecf20Sopenharmony_ci "clk_prepare_enable failed: %d\n", ret); 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci rate = clk_get_rate(i2c->clk) / 1000; 7948c2ecf20Sopenharmony_ci if (rate) 7958c2ecf20Sopenharmony_ci i2c->ip_clock_khz = rate; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci return ocores_init(dev, i2c); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); 8018c2ecf20Sopenharmony_ci#define OCORES_I2C_PM (&ocores_i2c_pm) 8028c2ecf20Sopenharmony_ci#else 8038c2ecf20Sopenharmony_ci#define OCORES_I2C_PM NULL 8048c2ecf20Sopenharmony_ci#endif 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic struct platform_driver ocores_i2c_driver = { 8078c2ecf20Sopenharmony_ci .probe = ocores_i2c_probe, 8088c2ecf20Sopenharmony_ci .remove = ocores_i2c_remove, 8098c2ecf20Sopenharmony_ci .driver = { 8108c2ecf20Sopenharmony_ci .name = "ocores-i2c", 8118c2ecf20Sopenharmony_ci .of_match_table = ocores_i2c_match, 8128c2ecf20Sopenharmony_ci .pm = OCORES_I2C_PM, 8138c2ecf20Sopenharmony_ci }, 8148c2ecf20Sopenharmony_ci}; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cimodule_platform_driver(ocores_i2c_driver); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Korsgaard <peter@korsgaard.com>"); 8198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OpenCores I2C bus driver"); 8208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8218c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:ocores-i2c"); 822