brintos

brintos / linux-shallow public Read only

0
0
Text · 11.8 KiB · 0b0a1c4 Raw
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