478 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip CoreI2C I2C controller driver4 *5 * Copyright (c) 2018-2022 Microchip Corporation. All rights reserved.6 *7 * Author: Daire McNamara <daire.mcnamara@microchip.com>8 * Author: Conor Dooley <conor.dooley@microchip.com>9 */10#include <linux/clk.h>11#include <linux/clkdev.h>12#include <linux/err.h>13#include <linux/i2c.h>14#include <linux/interrupt.h>15#include <linux/io.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/platform_device.h>19 20#define CORE_I2C_CTRL (0x00)21#define CTRL_CR0 BIT(0)22#define CTRL_CR1 BIT(1)23#define CTRL_AA BIT(2)24#define CTRL_SI BIT(3)25#define CTRL_STO BIT(4)26#define CTRL_STA BIT(5)27#define CTRL_ENS1 BIT(6)28#define CTRL_CR2 BIT(7)29 30#define STATUS_BUS_ERROR (0x00)31#define STATUS_M_START_SENT (0x08)32#define STATUS_M_REPEATED_START_SENT (0x10)33#define STATUS_M_SLAW_ACK (0x18)34#define STATUS_M_SLAW_NACK (0x20)35#define STATUS_M_TX_DATA_ACK (0x28)36#define STATUS_M_TX_DATA_NACK (0x30)37#define STATUS_M_ARB_LOST (0x38)38#define STATUS_M_SLAR_ACK (0x40)39#define STATUS_M_SLAR_NACK (0x48)40#define STATUS_M_RX_DATA_ACKED (0x50)41#define STATUS_M_RX_DATA_NACKED (0x58)42#define STATUS_S_SLAW_ACKED (0x60)43#define STATUS_S_ARB_LOST_SLAW_ACKED (0x68)44#define STATUS_S_GENERAL_CALL_ACKED (0x70)45#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED (0x78)46#define STATUS_S_RX_DATA_ACKED (0x80)47#define STATUS_S_RX_DATA_NACKED (0x88)48#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED (0x90)49#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED (0x98)50#define STATUS_S_RX_STOP (0xA0)51#define STATUS_S_SLAR_ACKED (0xA8)52#define STATUS_S_ARB_LOST_SLAR_ACKED (0xB0)53#define STATUS_S_TX_DATA_ACK (0xB8)54#define STATUS_S_TX_DATA_NACK (0xC0)55#define STATUS_LAST_DATA_ACK (0xC8)56#define STATUS_M_SMB_MASTER_RESET (0xD0)57#define STATUS_S_SCL_LOW_TIMEOUT (0xD8) /* 25 ms */58#define STATUS_NO_STATE_INFO (0xF8)59 60#define CORE_I2C_STATUS (0x04)61#define CORE_I2C_DATA (0x08)62#define WRITE_BIT (0x0)63#define READ_BIT (0x1)64#define SLAVE_ADDR_SHIFT (1)65#define CORE_I2C_SLAVE0_ADDR (0x0c)66#define GENERAL_CALL_BIT (0x0)67#define CORE_I2C_SMBUS (0x10)68#define SMBALERT_INT_ENB (0x0)69#define SMBSUS_INT_ENB (0x1)70#define SMBUS_ENB (0x2)71#define SMBALERT_NI_STATUS (0x3)72#define SMBALERT_NO_CTRL (0x4)73#define SMBSUS_NI_STATUS (0x5)74#define SMBSUS_NO_CTRL (0x6)75#define SMBUS_RESET (0x7)76#define CORE_I2C_FREQ (0x14)77#define CORE_I2C_GLITCHREG (0x18)78#define CORE_I2C_SLAVE1_ADDR (0x1c)79 80#define PCLK_DIV_960 (CTRL_CR2)81#define PCLK_DIV_256 (0)82#define PCLK_DIV_224 (CTRL_CR0)83#define PCLK_DIV_192 (CTRL_CR1)84#define PCLK_DIV_160 (CTRL_CR0 | CTRL_CR1)85#define PCLK_DIV_120 (CTRL_CR0 | CTRL_CR2)86#define PCLK_DIV_60 (CTRL_CR1 | CTRL_CR2)87#define BCLK_DIV_8 (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)88#define CLK_MASK (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)89 90/**91 * struct mchp_corei2c_dev - Microchip CoreI2C device private data92 *93 * @base: pointer to register struct94 * @dev: device reference95 * @i2c_clk: clock reference for i2c input clock96 * @buf: pointer to msg buffer for easier use97 * @msg_complete: xfer completion object98 * @adapter: core i2c abstraction99 * @msg_err: error code for completed message100 * @bus_clk_rate: current i2c bus clock rate101 * @isr_status: cached copy of local ISR status102 * @msg_len: number of bytes transferred in msg103 * @addr: address of the current slave104 */105struct mchp_corei2c_dev {106 void __iomem *base;107 struct device *dev;108 struct clk *i2c_clk;109 u8 *buf;110 struct completion msg_complete;111 struct i2c_adapter adapter;112 int msg_err;113 u32 bus_clk_rate;114 u32 isr_status;115 u16 msg_len;116 u8 addr;117};118 119static void mchp_corei2c_core_disable(struct mchp_corei2c_dev *idev)120{121 u8 ctrl = readb(idev->base + CORE_I2C_CTRL);122 123 ctrl &= ~CTRL_ENS1;124 writeb(ctrl, idev->base + CORE_I2C_CTRL);125}126 127static void mchp_corei2c_core_enable(struct mchp_corei2c_dev *idev)128{129 u8 ctrl = readb(idev->base + CORE_I2C_CTRL);130 131 ctrl |= CTRL_ENS1;132 writeb(ctrl, idev->base + CORE_I2C_CTRL);133}134 135static void mchp_corei2c_reset(struct mchp_corei2c_dev *idev)136{137 mchp_corei2c_core_disable(idev);138 mchp_corei2c_core_enable(idev);139}140 141static inline void mchp_corei2c_stop(struct mchp_corei2c_dev *idev)142{143 u8 ctrl = readb(idev->base + CORE_I2C_CTRL);144 145 ctrl |= CTRL_STO;146 writeb(ctrl, idev->base + CORE_I2C_CTRL);147}148 149static inline int mchp_corei2c_set_divisor(u32 rate,150 struct mchp_corei2c_dev *idev)151{152 u8 clkval, ctrl;153 154 if (rate >= 960)155 clkval = PCLK_DIV_960;156 else if (rate >= 256)157 clkval = PCLK_DIV_256;158 else if (rate >= 224)159 clkval = PCLK_DIV_224;160 else if (rate >= 192)161 clkval = PCLK_DIV_192;162 else if (rate >= 160)163 clkval = PCLK_DIV_160;164 else if (rate >= 120)165 clkval = PCLK_DIV_120;166 else if (rate >= 60)167 clkval = PCLK_DIV_60;168 else if (rate >= 8)169 clkval = BCLK_DIV_8;170 else171 return -EINVAL;172 173 ctrl = readb(idev->base + CORE_I2C_CTRL);174 ctrl &= ~CLK_MASK;175 ctrl |= clkval;176 writeb(ctrl, idev->base + CORE_I2C_CTRL);177 178 ctrl = readb(idev->base + CORE_I2C_CTRL);179 if ((ctrl & CLK_MASK) != clkval)180 return -EIO;181 182 return 0;183}184 185static int mchp_corei2c_init(struct mchp_corei2c_dev *idev)186{187 u32 clk_rate = clk_get_rate(idev->i2c_clk);188 u32 divisor = clk_rate / idev->bus_clk_rate;189 int ret;190 191 ret = mchp_corei2c_set_divisor(divisor, idev);192 if (ret)193 return ret;194 195 mchp_corei2c_reset(idev);196 197 return 0;198}199 200static void mchp_corei2c_empty_rx(struct mchp_corei2c_dev *idev)201{202 u8 ctrl;203 204 if (idev->msg_len > 0) {205 *idev->buf++ = readb(idev->base + CORE_I2C_DATA);206 idev->msg_len--;207 }208 209 if (idev->msg_len <= 1) {210 ctrl = readb(idev->base + CORE_I2C_CTRL);211 ctrl &= ~CTRL_AA;212 writeb(ctrl, idev->base + CORE_I2C_CTRL);213 }214}215 216static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev)217{218 if (idev->msg_len > 0)219 writeb(*idev->buf++, idev->base + CORE_I2C_DATA);220 idev->msg_len--;221 222 return 0;223}224 225static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)226{227 u32 status = idev->isr_status;228 u8 ctrl;229 bool last_byte = false, finished = false;230 231 if (!idev->buf)232 return IRQ_NONE;233 234 switch (status) {235 case STATUS_M_START_SENT:236 case STATUS_M_REPEATED_START_SENT:237 ctrl = readb(idev->base + CORE_I2C_CTRL);238 ctrl &= ~CTRL_STA;239 writeb(idev->addr, idev->base + CORE_I2C_DATA);240 writeb(ctrl, idev->base + CORE_I2C_CTRL);241 if (idev->msg_len == 0)242 finished = true;243 break;244 case STATUS_M_ARB_LOST:245 idev->msg_err = -EAGAIN;246 finished = true;247 break;248 case STATUS_M_SLAW_ACK:249 case STATUS_M_TX_DATA_ACK:250 if (idev->msg_len > 0)251 mchp_corei2c_fill_tx(idev);252 else253 last_byte = true;254 break;255 case STATUS_M_TX_DATA_NACK:256 case STATUS_M_SLAR_NACK:257 case STATUS_M_SLAW_NACK:258 idev->msg_err = -ENXIO;259 last_byte = true;260 break;261 case STATUS_M_SLAR_ACK:262 ctrl = readb(idev->base + CORE_I2C_CTRL);263 if (idev->msg_len == 1u) {264 ctrl &= ~CTRL_AA;265 writeb(ctrl, idev->base + CORE_I2C_CTRL);266 } else {267 ctrl |= CTRL_AA;268 writeb(ctrl, idev->base + CORE_I2C_CTRL);269 }270 if (idev->msg_len < 1u)271 last_byte = true;272 break;273 case STATUS_M_RX_DATA_ACKED:274 mchp_corei2c_empty_rx(idev);275 break;276 case STATUS_M_RX_DATA_NACKED:277 mchp_corei2c_empty_rx(idev);278 if (idev->msg_len == 0)279 last_byte = true;280 break;281 default:282 break;283 }284 285 /* On the last byte to be transmitted, send STOP */286 if (last_byte)287 mchp_corei2c_stop(idev);288 289 if (last_byte || finished)290 complete(&idev->msg_complete);291 292 return IRQ_HANDLED;293}294 295static irqreturn_t mchp_corei2c_isr(int irq, void *_dev)296{297 struct mchp_corei2c_dev *idev = _dev;298 irqreturn_t ret = IRQ_NONE;299 u8 ctrl;300 301 ctrl = readb(idev->base + CORE_I2C_CTRL);302 if (ctrl & CTRL_SI) {303 idev->isr_status = readb(idev->base + CORE_I2C_STATUS);304 ret = mchp_corei2c_handle_isr(idev);305 }306 307 ctrl = readb(idev->base + CORE_I2C_CTRL);308 ctrl &= ~CTRL_SI;309 writeb(ctrl, idev->base + CORE_I2C_CTRL);310 311 return ret;312}313 314static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,315 struct i2c_msg *msg)316{317 u8 ctrl;318 unsigned long time_left;319 320 idev->addr = i2c_8bit_addr_from_msg(msg);321 idev->msg_len = msg->len;322 idev->buf = msg->buf;323 idev->msg_err = 0;324 325 reinit_completion(&idev->msg_complete);326 327 mchp_corei2c_core_enable(idev);328 329 ctrl = readb(idev->base + CORE_I2C_CTRL);330 ctrl |= CTRL_STA;331 writeb(ctrl, idev->base + CORE_I2C_CTRL);332 333 time_left = wait_for_completion_timeout(&idev->msg_complete,334 idev->adapter.timeout);335 if (!time_left)336 return -ETIMEDOUT;337 338 return idev->msg_err;339}340 341static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,342 int num)343{344 struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);345 int i, ret;346 347 for (i = 0; i < num; i++) {348 ret = mchp_corei2c_xfer_msg(idev, msgs++);349 if (ret)350 return ret;351 }352 353 return num;354}355 356static u32 mchp_corei2c_func(struct i2c_adapter *adap)357{358 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;359}360 361static const struct i2c_algorithm mchp_corei2c_algo = {362 .master_xfer = mchp_corei2c_xfer,363 .functionality = mchp_corei2c_func,364};365 366static int mchp_corei2c_probe(struct platform_device *pdev)367{368 struct mchp_corei2c_dev *idev;369 struct resource *res;370 int irq, ret;371 372 idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);373 if (!idev)374 return -ENOMEM;375 376 idev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);377 if (IS_ERR(idev->base))378 return PTR_ERR(idev->base);379 380 irq = platform_get_irq(pdev, 0);381 if (irq < 0)382 return irq;383 384 idev->i2c_clk = devm_clk_get(&pdev->dev, NULL);385 if (IS_ERR(idev->i2c_clk))386 return dev_err_probe(&pdev->dev, PTR_ERR(idev->i2c_clk),387 "missing clock\n");388 389 idev->dev = &pdev->dev;390 init_completion(&idev->msg_complete);391 392 ret = device_property_read_u32(idev->dev, "clock-frequency",393 &idev->bus_clk_rate);394 if (ret || !idev->bus_clk_rate) {395 dev_info(&pdev->dev, "default to 100kHz\n");396 idev->bus_clk_rate = 100000;397 }398 399 if (idev->bus_clk_rate > 400000)400 return dev_err_probe(&pdev->dev, -EINVAL,401 "clock-frequency too high: %d\n",402 idev->bus_clk_rate);403 404 /*405 * This driver supports both the hard peripherals & soft FPGA cores.406 * The hard peripherals do not have shared IRQs, but we don't have407 * control over what way the interrupts are wired for the soft cores.408 */409 ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED,410 pdev->name, idev);411 if (ret)412 return dev_err_probe(&pdev->dev, ret,413 "failed to claim irq %d\n", irq);414 415 ret = clk_prepare_enable(idev->i2c_clk);416 if (ret)417 return dev_err_probe(&pdev->dev, ret,418 "failed to enable clock\n");419 420 ret = mchp_corei2c_init(idev);421 if (ret) {422 clk_disable_unprepare(idev->i2c_clk);423 return dev_err_probe(&pdev->dev, ret, "failed to program clock divider\n");424 }425 426 i2c_set_adapdata(&idev->adapter, idev);427 snprintf(idev->adapter.name, sizeof(idev->adapter.name),428 "Microchip I2C hw bus at %08lx", (unsigned long)res->start);429 idev->adapter.owner = THIS_MODULE;430 idev->adapter.algo = &mchp_corei2c_algo;431 idev->adapter.dev.parent = &pdev->dev;432 idev->adapter.dev.of_node = pdev->dev.of_node;433 idev->adapter.timeout = HZ;434 435 platform_set_drvdata(pdev, idev);436 437 ret = i2c_add_adapter(&idev->adapter);438 if (ret) {439 clk_disable_unprepare(idev->i2c_clk);440 return ret;441 }442 443 dev_info(&pdev->dev, "registered CoreI2C bus driver\n");444 445 return 0;446}447 448static void mchp_corei2c_remove(struct platform_device *pdev)449{450 struct mchp_corei2c_dev *idev = platform_get_drvdata(pdev);451 452 clk_disable_unprepare(idev->i2c_clk);453 i2c_del_adapter(&idev->adapter);454}455 456static const struct of_device_id mchp_corei2c_of_match[] = {457 { .compatible = "microchip,mpfs-i2c" },458 { .compatible = "microchip,corei2c-rtl-v7" },459 {},460};461MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match);462 463static struct platform_driver mchp_corei2c_driver = {464 .probe = mchp_corei2c_probe,465 .remove_new = mchp_corei2c_remove,466 .driver = {467 .name = "microchip-corei2c",468 .of_match_table = mchp_corei2c_of_match,469 },470};471 472module_platform_driver(mchp_corei2c_driver);473 474MODULE_DESCRIPTION("Microchip CoreI2C bus driver");475MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");476MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");477MODULE_LICENSE("GPL");478