18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 NXP Semiconductors 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Code portions referenced from the i2x-pxa and i2c-pnx drivers 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Make SMBus byte and word transactions work on LPC178x/7x 88c2ecf20Sopenharmony_ci * Copyright (c) 2012 98c2ecf20Sopenharmony_ci * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com 108c2ecf20Sopenharmony_ci * Anton Protopopov, Emcraft Systems, antonp@emcraft.com 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_device.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/sched.h> 268c2ecf20Sopenharmony_ci#include <linux/time.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* LPC24xx register offsets and bits */ 298c2ecf20Sopenharmony_ci#define LPC24XX_I2CONSET 0x00 308c2ecf20Sopenharmony_ci#define LPC24XX_I2STAT 0x04 318c2ecf20Sopenharmony_ci#define LPC24XX_I2DAT 0x08 328c2ecf20Sopenharmony_ci#define LPC24XX_I2ADDR 0x0c 338c2ecf20Sopenharmony_ci#define LPC24XX_I2SCLH 0x10 348c2ecf20Sopenharmony_ci#define LPC24XX_I2SCLL 0x14 358c2ecf20Sopenharmony_ci#define LPC24XX_I2CONCLR 0x18 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define LPC24XX_AA BIT(2) 388c2ecf20Sopenharmony_ci#define LPC24XX_SI BIT(3) 398c2ecf20Sopenharmony_ci#define LPC24XX_STO BIT(4) 408c2ecf20Sopenharmony_ci#define LPC24XX_STA BIT(5) 418c2ecf20Sopenharmony_ci#define LPC24XX_I2EN BIT(6) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define LPC24XX_STO_AA (LPC24XX_STO | LPC24XX_AA) 448c2ecf20Sopenharmony_ci#define LPC24XX_CLEAR_ALL (LPC24XX_AA | LPC24XX_SI | LPC24XX_STO | \ 458c2ecf20Sopenharmony_ci LPC24XX_STA | LPC24XX_I2EN) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* I2C SCL clock has different duty cycle depending on mode */ 488c2ecf20Sopenharmony_ci#define I2C_STD_MODE_DUTY 46 498c2ecf20Sopenharmony_ci#define I2C_FAST_MODE_DUTY 36 508c2ecf20Sopenharmony_ci#define I2C_FAST_MODE_PLUS_DUTY 38 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * 26 possible I2C status codes, but codes applicable only 548c2ecf20Sopenharmony_ci * to master are listed here and used in this driver 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cienum { 578c2ecf20Sopenharmony_ci M_BUS_ERROR = 0x00, 588c2ecf20Sopenharmony_ci M_START = 0x08, 598c2ecf20Sopenharmony_ci M_REPSTART = 0x10, 608c2ecf20Sopenharmony_ci MX_ADDR_W_ACK = 0x18, 618c2ecf20Sopenharmony_ci MX_ADDR_W_NACK = 0x20, 628c2ecf20Sopenharmony_ci MX_DATA_W_ACK = 0x28, 638c2ecf20Sopenharmony_ci MX_DATA_W_NACK = 0x30, 648c2ecf20Sopenharmony_ci M_DATA_ARB_LOST = 0x38, 658c2ecf20Sopenharmony_ci MR_ADDR_R_ACK = 0x40, 668c2ecf20Sopenharmony_ci MR_ADDR_R_NACK = 0x48, 678c2ecf20Sopenharmony_ci MR_DATA_R_ACK = 0x50, 688c2ecf20Sopenharmony_ci MR_DATA_R_NACK = 0x58, 698c2ecf20Sopenharmony_ci M_I2C_IDLE = 0xf8, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct lpc2k_i2c { 738c2ecf20Sopenharmony_ci void __iomem *base; 748c2ecf20Sopenharmony_ci struct clk *clk; 758c2ecf20Sopenharmony_ci int irq; 768c2ecf20Sopenharmony_ci wait_queue_head_t wait; 778c2ecf20Sopenharmony_ci struct i2c_adapter adap; 788c2ecf20Sopenharmony_ci struct i2c_msg *msg; 798c2ecf20Sopenharmony_ci int msg_idx; 808c2ecf20Sopenharmony_ci int msg_status; 818c2ecf20Sopenharmony_ci int is_last; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void i2c_lpc2k_reset(struct lpc2k_i2c *i2c) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci /* Will force clear all statuses */ 878c2ecf20Sopenharmony_ci writel(LPC24XX_CLEAR_ALL, i2c->base + LPC24XX_I2CONCLR); 888c2ecf20Sopenharmony_ci writel(0, i2c->base + LPC24XX_I2ADDR); 898c2ecf20Sopenharmony_ci writel(LPC24XX_I2EN, i2c->base + LPC24XX_I2CONSET); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int i2c_lpc2k_clear_arb(struct lpc2k_i2c *i2c) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * If the transfer needs to abort for some reason, we'll try to 988c2ecf20Sopenharmony_ci * force a stop condition to clear any pending bus conditions 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci writel(LPC24XX_STO, i2c->base + LPC24XX_I2CONSET); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Wait for status change */ 1038c2ecf20Sopenharmony_ci while (readl(i2c->base + LPC24XX_I2STAT) != M_I2C_IDLE) { 1048c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 1058c2ecf20Sopenharmony_ci /* Bus was not idle, try to reset adapter */ 1068c2ecf20Sopenharmony_ci i2c_lpc2k_reset(i2c); 1078c2ecf20Sopenharmony_ci return -EBUSY; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci cpu_relax(); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci unsigned char data; 1198c2ecf20Sopenharmony_ci u32 status; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * I2C in the LPC2xxx series is basically a state machine. 1238c2ecf20Sopenharmony_ci * Just run through the steps based on the current status. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci status = readl(i2c->base + LPC24XX_I2STAT); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci switch (status) { 1288c2ecf20Sopenharmony_ci case M_START: 1298c2ecf20Sopenharmony_ci case M_REPSTART: 1308c2ecf20Sopenharmony_ci /* Start bit was just sent out, send out addr and dir */ 1318c2ecf20Sopenharmony_ci data = i2c_8bit_addr_from_msg(i2c->msg); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci writel(data, i2c->base + LPC24XX_I2DAT); 1348c2ecf20Sopenharmony_ci writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci case MX_ADDR_W_ACK: 1388c2ecf20Sopenharmony_ci case MX_DATA_W_ACK: 1398c2ecf20Sopenharmony_ci /* 1408c2ecf20Sopenharmony_ci * Address or data was sent out with an ACK. If there is more 1418c2ecf20Sopenharmony_ci * data to send, send it now 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci if (i2c->msg_idx < i2c->msg->len) { 1448c2ecf20Sopenharmony_ci writel(i2c->msg->buf[i2c->msg_idx], 1458c2ecf20Sopenharmony_ci i2c->base + LPC24XX_I2DAT); 1468c2ecf20Sopenharmony_ci } else if (i2c->is_last) { 1478c2ecf20Sopenharmony_ci /* Last message, send stop */ 1488c2ecf20Sopenharmony_ci writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); 1498c2ecf20Sopenharmony_ci writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); 1508c2ecf20Sopenharmony_ci i2c->msg_status = 0; 1518c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci i2c->msg_status = 0; 1548c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci i2c->msg_idx++; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci case MR_ADDR_R_ACK: 1618c2ecf20Sopenharmony_ci /* Receive first byte from slave */ 1628c2ecf20Sopenharmony_ci if (i2c->msg->len == 1) { 1638c2ecf20Sopenharmony_ci /* Last byte, return NACK */ 1648c2ecf20Sopenharmony_ci writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); 1658c2ecf20Sopenharmony_ci } else { 1668c2ecf20Sopenharmony_ci /* Not last byte, return ACK */ 1678c2ecf20Sopenharmony_ci writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci case MR_DATA_R_NACK: 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * The I2C shows NACK status on reads, so we need to accept 1768c2ecf20Sopenharmony_ci * the NACK as an ACK here. This should be ok, as the real 1778c2ecf20Sopenharmony_ci * BACK would of been caught on the address write. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci case MR_DATA_R_ACK: 1808c2ecf20Sopenharmony_ci /* Data was received */ 1818c2ecf20Sopenharmony_ci if (i2c->msg_idx < i2c->msg->len) { 1828c2ecf20Sopenharmony_ci i2c->msg->buf[i2c->msg_idx] = 1838c2ecf20Sopenharmony_ci readl(i2c->base + LPC24XX_I2DAT); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* If transfer is done, send STOP */ 1878c2ecf20Sopenharmony_ci if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) { 1888c2ecf20Sopenharmony_ci writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); 1898c2ecf20Sopenharmony_ci writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); 1908c2ecf20Sopenharmony_ci i2c->msg_status = 0; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Message is done */ 1948c2ecf20Sopenharmony_ci if (i2c->msg_idx >= i2c->msg->len - 1) { 1958c2ecf20Sopenharmony_ci i2c->msg_status = 0; 1968c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* 2008c2ecf20Sopenharmony_ci * One pre-last data input, send NACK to tell the slave that 2018c2ecf20Sopenharmony_ci * this is going to be the last data byte to be transferred. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci if (i2c->msg_idx >= i2c->msg->len - 2) { 2048c2ecf20Sopenharmony_ci /* One byte left to receive - NACK */ 2058c2ecf20Sopenharmony_ci writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci /* More than one byte left to receive - ACK */ 2088c2ecf20Sopenharmony_ci writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); 2128c2ecf20Sopenharmony_ci i2c->msg_idx++; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci case MX_ADDR_W_NACK: 2168c2ecf20Sopenharmony_ci case MX_DATA_W_NACK: 2178c2ecf20Sopenharmony_ci case MR_ADDR_R_NACK: 2188c2ecf20Sopenharmony_ci /* NACK processing is done */ 2198c2ecf20Sopenharmony_ci writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); 2208c2ecf20Sopenharmony_ci i2c->msg_status = -ENXIO; 2218c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci case M_DATA_ARB_LOST: 2258c2ecf20Sopenharmony_ci /* Arbitration lost */ 2268c2ecf20Sopenharmony_ci i2c->msg_status = -EAGAIN; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Release the I2C bus */ 2298c2ecf20Sopenharmony_ci writel(LPC24XX_STA | LPC24XX_STO, i2c->base + LPC24XX_I2CONCLR); 2308c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci default: 2348c2ecf20Sopenharmony_ci /* Unexpected statuses */ 2358c2ecf20Sopenharmony_ci i2c->msg_status = -EIO; 2368c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Exit on failure or all bytes transferred */ 2418c2ecf20Sopenharmony_ci if (i2c->msg_status != -EBUSY) 2428c2ecf20Sopenharmony_ci wake_up(&i2c->wait); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * If `msg_status` is zero, then `lpc2k_process_msg()` 2468c2ecf20Sopenharmony_ci * is responsible for clearing the SI flag. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci if (i2c->msg_status != 0) 2498c2ecf20Sopenharmony_ci writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int lpc2k_process_msg(struct lpc2k_i2c *i2c, int msgidx) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci /* A new transfer is kicked off by initiating a start condition */ 2558c2ecf20Sopenharmony_ci if (!msgidx) { 2568c2ecf20Sopenharmony_ci writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); 2578c2ecf20Sopenharmony_ci } else { 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * A multi-message I2C transfer continues where the 2608c2ecf20Sopenharmony_ci * previous I2C transfer left off and uses the 2618c2ecf20Sopenharmony_ci * current condition of the I2C adapter. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) { 2648c2ecf20Sopenharmony_ci WARN_ON(i2c->msg->len == 0); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!(i2c->msg->flags & I2C_M_RD)) { 2678c2ecf20Sopenharmony_ci /* Start transmit of data */ 2688c2ecf20Sopenharmony_ci writel(i2c->msg->buf[0], 2698c2ecf20Sopenharmony_ci i2c->base + LPC24XX_I2DAT); 2708c2ecf20Sopenharmony_ci i2c->msg_idx++; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci /* Start or repeated start */ 2748c2ecf20Sopenharmony_ci writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci enable_irq(i2c->irq); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Wait for transfer completion */ 2838c2ecf20Sopenharmony_ci if (wait_event_timeout(i2c->wait, i2c->msg_status != -EBUSY, 2848c2ecf20Sopenharmony_ci msecs_to_jiffies(1000)) == 0) { 2858c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return i2c->msg_status; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 2948c2ecf20Sopenharmony_ci int msg_num) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c = i2c_get_adapdata(adap); 2978c2ecf20Sopenharmony_ci int ret, i; 2988c2ecf20Sopenharmony_ci u32 stat; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Check for bus idle condition */ 3018c2ecf20Sopenharmony_ci stat = readl(i2c->base + LPC24XX_I2STAT); 3028c2ecf20Sopenharmony_ci if (stat != M_I2C_IDLE) { 3038c2ecf20Sopenharmony_ci /* Something is holding the bus, try to clear it */ 3048c2ecf20Sopenharmony_ci return i2c_lpc2k_clear_arb(i2c); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Process a single message at a time */ 3088c2ecf20Sopenharmony_ci for (i = 0; i < msg_num; i++) { 3098c2ecf20Sopenharmony_ci /* Save message pointer and current message data index */ 3108c2ecf20Sopenharmony_ci i2c->msg = &msgs[i]; 3118c2ecf20Sopenharmony_ci i2c->msg_idx = 0; 3128c2ecf20Sopenharmony_ci i2c->msg_status = -EBUSY; 3138c2ecf20Sopenharmony_ci i2c->is_last = (i == (msg_num - 1)); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = lpc2k_process_msg(i2c, i); 3168c2ecf20Sopenharmony_ci if (ret) 3178c2ecf20Sopenharmony_ci return ret; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return msg_num; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic irqreturn_t i2c_lpc2k_handler(int irq, void *dev_id) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c = dev_id; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (readl(i2c->base + LPC24XX_I2CONSET) & LPC24XX_SI) { 3288c2ecf20Sopenharmony_ci i2c_lpc2k_pump_msg(i2c); 3298c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return IRQ_NONE; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic u32 i2c_lpc2k_functionality(struct i2c_adapter *adap) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci /* Only emulated SMBus for now */ 3388c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic const struct i2c_algorithm i2c_lpc2k_algorithm = { 3428c2ecf20Sopenharmony_ci .master_xfer = i2c_lpc2k_xfer, 3438c2ecf20Sopenharmony_ci .functionality = i2c_lpc2k_functionality, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int i2c_lpc2k_probe(struct platform_device *pdev) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c; 3498c2ecf20Sopenharmony_ci u32 bus_clk_rate; 3508c2ecf20Sopenharmony_ci u32 scl_high; 3518c2ecf20Sopenharmony_ci u32 clkrate; 3528c2ecf20Sopenharmony_ci int ret; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); 3558c2ecf20Sopenharmony_ci if (!i2c) 3568c2ecf20Sopenharmony_ci return -ENOMEM; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci i2c->base = devm_platform_ioremap_resource(pdev, 0); 3598c2ecf20Sopenharmony_ci if (IS_ERR(i2c->base)) 3608c2ecf20Sopenharmony_ci return PTR_ERR(i2c->base); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci i2c->irq = platform_get_irq(pdev, 0); 3638c2ecf20Sopenharmony_ci if (i2c->irq < 0) 3648c2ecf20Sopenharmony_ci return i2c->irq; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci init_waitqueue_head(&i2c->wait); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, NULL); 3698c2ecf20Sopenharmony_ci if (IS_ERR(i2c->clk)) { 3708c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "error getting clock\n"); 3718c2ecf20Sopenharmony_ci return PTR_ERR(i2c->clk); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c->clk); 3758c2ecf20Sopenharmony_ci if (ret) { 3768c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to enable clock.\n"); 3778c2ecf20Sopenharmony_ci return ret; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, i2c->irq, i2c_lpc2k_handler, 0, 3818c2ecf20Sopenharmony_ci dev_name(&pdev->dev), i2c); 3828c2ecf20Sopenharmony_ci if (ret < 0) { 3838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't request interrupt.\n"); 3848c2ecf20Sopenharmony_ci goto fail_clk; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci disable_irq_nosync(i2c->irq); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Place controller is a known state */ 3908c2ecf20Sopenharmony_ci i2c_lpc2k_reset(i2c); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", 3938c2ecf20Sopenharmony_ci &bus_clk_rate); 3948c2ecf20Sopenharmony_ci if (ret) 3958c2ecf20Sopenharmony_ci bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci clkrate = clk_get_rate(i2c->clk); 3988c2ecf20Sopenharmony_ci if (clkrate == 0) { 3998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't get I2C base clock\n"); 4008c2ecf20Sopenharmony_ci ret = -EINVAL; 4018c2ecf20Sopenharmony_ci goto fail_clk; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Setup I2C dividers to generate clock with proper duty cycle */ 4058c2ecf20Sopenharmony_ci clkrate = clkrate / bus_clk_rate; 4068c2ecf20Sopenharmony_ci if (bus_clk_rate <= I2C_MAX_STANDARD_MODE_FREQ) 4078c2ecf20Sopenharmony_ci scl_high = (clkrate * I2C_STD_MODE_DUTY) / 100; 4088c2ecf20Sopenharmony_ci else if (bus_clk_rate <= I2C_MAX_FAST_MODE_FREQ) 4098c2ecf20Sopenharmony_ci scl_high = (clkrate * I2C_FAST_MODE_DUTY) / 100; 4108c2ecf20Sopenharmony_ci else 4118c2ecf20Sopenharmony_ci scl_high = (clkrate * I2C_FAST_MODE_PLUS_DUTY) / 100; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci writel(scl_high, i2c->base + LPC24XX_I2SCLH); 4148c2ecf20Sopenharmony_ci writel(clkrate - scl_high, i2c->base + LPC24XX_I2SCLL); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, i2c); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci i2c_set_adapdata(&i2c->adap, i2c); 4198c2ecf20Sopenharmony_ci i2c->adap.owner = THIS_MODULE; 4208c2ecf20Sopenharmony_ci strlcpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name)); 4218c2ecf20Sopenharmony_ci i2c->adap.algo = &i2c_lpc2k_algorithm; 4228c2ecf20Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 4238c2ecf20Sopenharmony_ci i2c->adap.dev.of_node = pdev->dev.of_node; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&i2c->adap); 4268c2ecf20Sopenharmony_ci if (ret < 0) 4278c2ecf20Sopenharmony_ci goto fail_clk; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "LPC2K I2C adapter\n"); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cifail_clk: 4348c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 4358c2ecf20Sopenharmony_ci return ret; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int i2c_lpc2k_remove(struct platform_device *dev) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c = platform_get_drvdata(dev); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c->adap); 4438c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4498c2ecf20Sopenharmony_cistatic int i2c_lpc2k_suspend(struct device *dev) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c = dev_get_drvdata(dev); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci clk_disable(i2c->clk); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int i2c_lpc2k_resume(struct device *dev) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct lpc2k_i2c *i2c = dev_get_drvdata(dev); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci clk_enable(i2c->clk); 4638c2ecf20Sopenharmony_ci i2c_lpc2k_reset(i2c); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = { 4698c2ecf20Sopenharmony_ci .suspend_noirq = i2c_lpc2k_suspend, 4708c2ecf20Sopenharmony_ci .resume_noirq = i2c_lpc2k_resume, 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops) 4748c2ecf20Sopenharmony_ci#else 4758c2ecf20Sopenharmony_ci#define I2C_LPC2K_DEV_PM_OPS NULL 4768c2ecf20Sopenharmony_ci#endif 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic const struct of_device_id lpc2k_i2c_match[] = { 4798c2ecf20Sopenharmony_ci { .compatible = "nxp,lpc1788-i2c" }, 4808c2ecf20Sopenharmony_ci {}, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lpc2k_i2c_match); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic struct platform_driver i2c_lpc2k_driver = { 4858c2ecf20Sopenharmony_ci .probe = i2c_lpc2k_probe, 4868c2ecf20Sopenharmony_ci .remove = i2c_lpc2k_remove, 4878c2ecf20Sopenharmony_ci .driver = { 4888c2ecf20Sopenharmony_ci .name = "lpc2k-i2c", 4898c2ecf20Sopenharmony_ci .pm = I2C_LPC2K_DEV_PM_OPS, 4908c2ecf20Sopenharmony_ci .of_match_table = lpc2k_i2c_match, 4918c2ecf20Sopenharmony_ci }, 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_cimodule_platform_driver(i2c_lpc2k_driver); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); 4968c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("I2C driver for LPC2xxx devices"); 4978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4988c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:lpc2k-i2c"); 499