brintos

brintos / linux-shallow public Read only

0
0
Text · 13.6 KiB · 5079442 Raw
555 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Copyright (c) 2021 MediaTek Inc.4 5#include <linux/clk.h>6#include <linux/iopoll.h>7#include <linux/module.h>8#include <linux/of.h>9#include <linux/platform_device.h>10#include <linux/property.h>11#include <linux/spmi.h>12 13#define SWINF_IDLE	0x0014#define SWINF_WFVLDCLR	0x0615 16#define GET_SWINF(x)	(((x) >> 1) & 0x7)17 18#define PMIF_CMD_REG_0		019#define PMIF_CMD_REG		120#define PMIF_CMD_EXT_REG	221#define PMIF_CMD_EXT_REG_LONG	322 23#define PMIF_DELAY_US   1024#define PMIF_TIMEOUT_US (10 * 1000)25 26#define PMIF_CHAN_OFFSET 0x527 28#define PMIF_MAX_CLKS	329 30#define SPMI_OP_ST_BUSY 131 32struct ch_reg {33	u32 ch_sta;34	u32 wdata;35	u32 rdata;36	u32 ch_send;37	u32 ch_rdy;38};39 40struct pmif_data {41	const u32	*regs;42	const u32	*spmimst_regs;43	u32	soc_chan;44};45 46struct pmif {47	void __iomem	*base;48	void __iomem	*spmimst_base;49	struct ch_reg	chan;50	struct clk_bulk_data clks[PMIF_MAX_CLKS];51	size_t nclks;52	const struct pmif_data *data;53	raw_spinlock_t lock;54};55 56static const char * const pmif_clock_names[] = {57	"pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",58};59 60enum pmif_regs {61	PMIF_INIT_DONE,62	PMIF_INF_EN,63	PMIF_ARB_EN,64	PMIF_CMDISSUE_EN,65	PMIF_TIMER_CTRL,66	PMIF_SPI_MODE_CTRL,67	PMIF_IRQ_EVENT_EN_0,68	PMIF_IRQ_FLAG_0,69	PMIF_IRQ_CLR_0,70	PMIF_IRQ_EVENT_EN_1,71	PMIF_IRQ_FLAG_1,72	PMIF_IRQ_CLR_1,73	PMIF_IRQ_EVENT_EN_2,74	PMIF_IRQ_FLAG_2,75	PMIF_IRQ_CLR_2,76	PMIF_IRQ_EVENT_EN_3,77	PMIF_IRQ_FLAG_3,78	PMIF_IRQ_CLR_3,79	PMIF_IRQ_EVENT_EN_4,80	PMIF_IRQ_FLAG_4,81	PMIF_IRQ_CLR_4,82	PMIF_WDT_EVENT_EN_0,83	PMIF_WDT_FLAG_0,84	PMIF_WDT_EVENT_EN_1,85	PMIF_WDT_FLAG_1,86	PMIF_SWINF_0_STA,87	PMIF_SWINF_0_WDATA_31_0,88	PMIF_SWINF_0_RDATA_31_0,89	PMIF_SWINF_0_ACC,90	PMIF_SWINF_0_VLD_CLR,91	PMIF_SWINF_1_STA,92	PMIF_SWINF_1_WDATA_31_0,93	PMIF_SWINF_1_RDATA_31_0,94	PMIF_SWINF_1_ACC,95	PMIF_SWINF_1_VLD_CLR,96	PMIF_SWINF_2_STA,97	PMIF_SWINF_2_WDATA_31_0,98	PMIF_SWINF_2_RDATA_31_0,99	PMIF_SWINF_2_ACC,100	PMIF_SWINF_2_VLD_CLR,101	PMIF_SWINF_3_STA,102	PMIF_SWINF_3_WDATA_31_0,103	PMIF_SWINF_3_RDATA_31_0,104	PMIF_SWINF_3_ACC,105	PMIF_SWINF_3_VLD_CLR,106};107 108static const u32 mt6873_regs[] = {109	[PMIF_INIT_DONE] = 0x0000,110	[PMIF_INF_EN] = 0x0024,111	[PMIF_ARB_EN] = 0x0150,112	[PMIF_CMDISSUE_EN] = 0x03B4,113	[PMIF_TIMER_CTRL] = 0x03E0,114	[PMIF_SPI_MODE_CTRL] = 0x0400,115	[PMIF_IRQ_EVENT_EN_0] = 0x0418,116	[PMIF_IRQ_FLAG_0] = 0x0420,117	[PMIF_IRQ_CLR_0] = 0x0424,118	[PMIF_IRQ_EVENT_EN_1] = 0x0428,119	[PMIF_IRQ_FLAG_1] = 0x0430,120	[PMIF_IRQ_CLR_1] = 0x0434,121	[PMIF_IRQ_EVENT_EN_2] = 0x0438,122	[PMIF_IRQ_FLAG_2] = 0x0440,123	[PMIF_IRQ_CLR_2] = 0x0444,124	[PMIF_IRQ_EVENT_EN_3] = 0x0448,125	[PMIF_IRQ_FLAG_3] = 0x0450,126	[PMIF_IRQ_CLR_3] = 0x0454,127	[PMIF_IRQ_EVENT_EN_4] = 0x0458,128	[PMIF_IRQ_FLAG_4] = 0x0460,129	[PMIF_IRQ_CLR_4] = 0x0464,130	[PMIF_WDT_EVENT_EN_0] = 0x046C,131	[PMIF_WDT_FLAG_0] = 0x0470,132	[PMIF_WDT_EVENT_EN_1] = 0x0474,133	[PMIF_WDT_FLAG_1] = 0x0478,134	[PMIF_SWINF_0_ACC] = 0x0C00,135	[PMIF_SWINF_0_WDATA_31_0] = 0x0C04,136	[PMIF_SWINF_0_RDATA_31_0] = 0x0C14,137	[PMIF_SWINF_0_VLD_CLR] = 0x0C24,138	[PMIF_SWINF_0_STA] = 0x0C28,139	[PMIF_SWINF_1_ACC] = 0x0C40,140	[PMIF_SWINF_1_WDATA_31_0] = 0x0C44,141	[PMIF_SWINF_1_RDATA_31_0] = 0x0C54,142	[PMIF_SWINF_1_VLD_CLR] = 0x0C64,143	[PMIF_SWINF_1_STA] = 0x0C68,144	[PMIF_SWINF_2_ACC] = 0x0C80,145	[PMIF_SWINF_2_WDATA_31_0] = 0x0C84,146	[PMIF_SWINF_2_RDATA_31_0] = 0x0C94,147	[PMIF_SWINF_2_VLD_CLR] = 0x0CA4,148	[PMIF_SWINF_2_STA] = 0x0CA8,149	[PMIF_SWINF_3_ACC] = 0x0CC0,150	[PMIF_SWINF_3_WDATA_31_0] = 0x0CC4,151	[PMIF_SWINF_3_RDATA_31_0] = 0x0CD4,152	[PMIF_SWINF_3_VLD_CLR] = 0x0CE4,153	[PMIF_SWINF_3_STA] = 0x0CE8,154};155 156static const u32 mt8195_regs[] = {157	[PMIF_INIT_DONE] = 0x0000,158	[PMIF_INF_EN] = 0x0024,159	[PMIF_ARB_EN] = 0x0150,160	[PMIF_CMDISSUE_EN] = 0x03B8,161	[PMIF_TIMER_CTRL] = 0x03E4,162	[PMIF_SPI_MODE_CTRL] = 0x0408,163	[PMIF_IRQ_EVENT_EN_0] = 0x0420,164	[PMIF_IRQ_FLAG_0] = 0x0428,165	[PMIF_IRQ_CLR_0] = 0x042C,166	[PMIF_IRQ_EVENT_EN_1] = 0x0430,167	[PMIF_IRQ_FLAG_1] = 0x0438,168	[PMIF_IRQ_CLR_1] = 0x043C,169	[PMIF_IRQ_EVENT_EN_2] = 0x0440,170	[PMIF_IRQ_FLAG_2] = 0x0448,171	[PMIF_IRQ_CLR_2] = 0x044C,172	[PMIF_IRQ_EVENT_EN_3] = 0x0450,173	[PMIF_IRQ_FLAG_3] = 0x0458,174	[PMIF_IRQ_CLR_3] = 0x045C,175	[PMIF_IRQ_EVENT_EN_4] = 0x0460,176	[PMIF_IRQ_FLAG_4] = 0x0468,177	[PMIF_IRQ_CLR_4] = 0x046C,178	[PMIF_WDT_EVENT_EN_0] = 0x0474,179	[PMIF_WDT_FLAG_0] = 0x0478,180	[PMIF_WDT_EVENT_EN_1] = 0x047C,181	[PMIF_WDT_FLAG_1] = 0x0480,182	[PMIF_SWINF_0_ACC] = 0x0800,183	[PMIF_SWINF_0_WDATA_31_0] = 0x0804,184	[PMIF_SWINF_0_RDATA_31_0] = 0x0814,185	[PMIF_SWINF_0_VLD_CLR] = 0x0824,186	[PMIF_SWINF_0_STA] = 0x0828,187	[PMIF_SWINF_1_ACC] = 0x0840,188	[PMIF_SWINF_1_WDATA_31_0] = 0x0844,189	[PMIF_SWINF_1_RDATA_31_0] = 0x0854,190	[PMIF_SWINF_1_VLD_CLR] = 0x0864,191	[PMIF_SWINF_1_STA] = 0x0868,192	[PMIF_SWINF_2_ACC] = 0x0880,193	[PMIF_SWINF_2_WDATA_31_0] = 0x0884,194	[PMIF_SWINF_2_RDATA_31_0] = 0x0894,195	[PMIF_SWINF_2_VLD_CLR] = 0x08A4,196	[PMIF_SWINF_2_STA] = 0x08A8,197	[PMIF_SWINF_3_ACC] = 0x08C0,198	[PMIF_SWINF_3_WDATA_31_0] = 0x08C4,199	[PMIF_SWINF_3_RDATA_31_0] = 0x08D4,200	[PMIF_SWINF_3_VLD_CLR] = 0x08E4,201	[PMIF_SWINF_3_STA] = 0x08E8,202};203 204enum spmi_regs {205	SPMI_OP_ST_CTRL,206	SPMI_GRP_ID_EN,207	SPMI_OP_ST_STA,208	SPMI_MST_SAMPL,209	SPMI_MST_REQ_EN,210	SPMI_REC_CTRL,211	SPMI_REC0,212	SPMI_REC1,213	SPMI_REC2,214	SPMI_REC3,215	SPMI_REC4,216	SPMI_MST_DBG,217 218	/* MT8195 spmi regs */219	SPMI_MST_RCS_CTRL,220	SPMI_SLV_3_0_EINT,221	SPMI_SLV_7_4_EINT,222	SPMI_SLV_B_8_EINT,223	SPMI_SLV_F_C_EINT,224	SPMI_REC_CMD_DEC,225	SPMI_DEC_DBG,226};227 228static const u32 mt6873_spmi_regs[] = {229	[SPMI_OP_ST_CTRL] = 0x0000,230	[SPMI_GRP_ID_EN] = 0x0004,231	[SPMI_OP_ST_STA] = 0x0008,232	[SPMI_MST_SAMPL] = 0x000c,233	[SPMI_MST_REQ_EN] = 0x0010,234	[SPMI_REC_CTRL] = 0x0040,235	[SPMI_REC0] = 0x0044,236	[SPMI_REC1] = 0x0048,237	[SPMI_REC2] = 0x004c,238	[SPMI_REC3] = 0x0050,239	[SPMI_REC4] = 0x0054,240	[SPMI_MST_DBG] = 0x00fc,241};242 243static const u32 mt8195_spmi_regs[] = {244	[SPMI_OP_ST_CTRL] = 0x0000,245	[SPMI_GRP_ID_EN] = 0x0004,246	[SPMI_OP_ST_STA] = 0x0008,247	[SPMI_MST_SAMPL] = 0x000C,248	[SPMI_MST_REQ_EN] = 0x0010,249	[SPMI_MST_RCS_CTRL] = 0x0014,250	[SPMI_SLV_3_0_EINT] = 0x0020,251	[SPMI_SLV_7_4_EINT] = 0x0024,252	[SPMI_SLV_B_8_EINT] = 0x0028,253	[SPMI_SLV_F_C_EINT] = 0x002C,254	[SPMI_REC_CTRL] = 0x0040,255	[SPMI_REC0] = 0x0044,256	[SPMI_REC1] = 0x0048,257	[SPMI_REC2] = 0x004C,258	[SPMI_REC3] = 0x0050,259	[SPMI_REC4] = 0x0054,260	[SPMI_REC_CMD_DEC] = 0x005C,261	[SPMI_DEC_DBG] = 0x00F8,262	[SPMI_MST_DBG] = 0x00FC,263};264 265static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)266{267	return readl(arb->base + arb->data->regs[reg]);268}269 270static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)271{272	writel(val, arb->base + arb->data->regs[reg]);273}274 275static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg)276{277	writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]);278}279 280static bool pmif_is_fsm_vldclr(struct pmif *arb)281{282	u32 reg_rdata;283 284	reg_rdata = pmif_readl(arb, arb->chan.ch_sta);285 286	return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR;287}288 289static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)290{291	struct pmif *arb = spmi_controller_get_drvdata(ctrl);292	u32 rdata, cmd;293	int ret;294 295	/* Check the opcode */296	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)297		return -EINVAL;298 299	cmd = opc - SPMI_CMD_RESET;300 301	mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);302	ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA],303					rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY,304					PMIF_DELAY_US, PMIF_TIMEOUT_US);305	if (ret < 0)306		dev_err(&ctrl->dev, "timeout, err = %d\n", ret);307 308	return ret;309}310 311static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,312			      u16 addr, u8 *buf, size_t len)313{314	struct pmif *arb = spmi_controller_get_drvdata(ctrl);315	struct ch_reg *inf_reg;316	int ret;317	u32 data, cmd;318	unsigned long flags;319 320	/* Check for argument validation. */321	if (sid & ~0xf) {322		dev_err(&ctrl->dev, "exceed the max slv id\n");323		return -EINVAL;324	}325 326	if (len > 4) {327		dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);328 329		return -EINVAL;330	}331 332	if (opc >= 0x60 && opc <= 0x7f)333		opc = PMIF_CMD_REG;334	else if ((opc >= 0x20 && opc <= 0x2f) || (opc >= 0x38 && opc <= 0x3f))335		opc = PMIF_CMD_EXT_REG_LONG;336	else337		return -EINVAL;338 339	raw_spin_lock_irqsave(&arb->lock, flags);340	/* Wait for Software Interface FSM state to be IDLE. */341	inf_reg = &arb->chan;342	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],343					data, GET_SWINF(data) == SWINF_IDLE,344					PMIF_DELAY_US, PMIF_TIMEOUT_US);345	if (ret < 0) {346		/* set channel ready if the data has transferred */347		if (pmif_is_fsm_vldclr(arb))348			pmif_writel(arb, 1, inf_reg->ch_rdy);349		raw_spin_unlock_irqrestore(&arb->lock, flags);350		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");351		return ret;352	}353 354	/* Send the command. */355	cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;356	pmif_writel(arb, cmd, inf_reg->ch_send);357	raw_spin_unlock_irqrestore(&arb->lock, flags);358 359	/*360	 * Wait for Software Interface FSM state to be WFVLDCLR,361	 * read the data and clear the valid flag.362	 */363	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],364					data, GET_SWINF(data) == SWINF_WFVLDCLR,365					PMIF_DELAY_US, PMIF_TIMEOUT_US);366	if (ret < 0) {367		dev_err(&ctrl->dev, "failed to wait for SWINF_WFVLDCLR\n");368		return ret;369	}370 371	data = pmif_readl(arb, inf_reg->rdata);372	memcpy(buf, &data, len);373	pmif_writel(arb, 1, inf_reg->ch_rdy);374 375	return 0;376}377 378static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,379			       u16 addr, const u8 *buf, size_t len)380{381	struct pmif *arb = spmi_controller_get_drvdata(ctrl);382	struct ch_reg *inf_reg;383	int ret;384	u32 data, wdata, cmd;385	unsigned long flags;386 387	/* Check for argument validation. */388	if (unlikely(sid & ~0xf)) {389		dev_err(&ctrl->dev, "exceed the max slv id\n");390		return -EINVAL;391	}392 393	if (len > 4) {394		dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);395 396		return -EINVAL;397	}398 399	/* Check the opcode */400	if (opc >= 0x40 && opc <= 0x5F)401		opc = PMIF_CMD_REG;402	else if ((opc <= 0xF) || (opc >= 0x30 && opc <= 0x37))403		opc = PMIF_CMD_EXT_REG_LONG;404	else if (opc >= 0x80)405		opc = PMIF_CMD_REG_0;406	else407		return -EINVAL;408 409	/* Set the write data. */410	memcpy(&wdata, buf, len);411 412	raw_spin_lock_irqsave(&arb->lock, flags);413	/* Wait for Software Interface FSM state to be IDLE. */414	inf_reg = &arb->chan;415	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],416					data, GET_SWINF(data) == SWINF_IDLE,417					PMIF_DELAY_US, PMIF_TIMEOUT_US);418	if (ret < 0) {419		/* set channel ready if the data has transferred */420		if (pmif_is_fsm_vldclr(arb))421			pmif_writel(arb, 1, inf_reg->ch_rdy);422		raw_spin_unlock_irqrestore(&arb->lock, flags);423		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");424		return ret;425	}426 427	pmif_writel(arb, wdata, inf_reg->wdata);428 429	/* Send the command. */430	cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;431	pmif_writel(arb, cmd, inf_reg->ch_send);432	raw_spin_unlock_irqrestore(&arb->lock, flags);433 434	return 0;435}436 437static const struct pmif_data mt6873_pmif_arb = {438	.regs = mt6873_regs,439	.spmimst_regs = mt6873_spmi_regs,440	.soc_chan = 2,441};442 443static const struct pmif_data mt8195_pmif_arb = {444	.regs = mt8195_regs,445	.spmimst_regs = mt8195_spmi_regs,446	.soc_chan = 2,447};448 449static int mtk_spmi_probe(struct platform_device *pdev)450{451	struct pmif *arb;452	struct spmi_controller *ctrl;453	int err, i;454	u32 chan_offset;455 456	ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*arb));457	if (IS_ERR(ctrl))458		return PTR_ERR(ctrl);459 460	arb = spmi_controller_get_drvdata(ctrl);461	arb->data = device_get_match_data(&pdev->dev);462	if (!arb->data) {463		dev_err(&pdev->dev, "Cannot get drv_data\n");464		return -EINVAL;465	}466 467	arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");468	if (IS_ERR(arb->base))469		return PTR_ERR(arb->base);470 471	arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");472	if (IS_ERR(arb->spmimst_base))473		return PTR_ERR(arb->spmimst_base);474 475	arb->nclks = ARRAY_SIZE(pmif_clock_names);476	for (i = 0; i < arb->nclks; i++)477		arb->clks[i].id = pmif_clock_names[i];478 479	err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);480	if (err) {481		dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);482		return err;483	}484 485	err = clk_bulk_prepare_enable(arb->nclks, arb->clks);486	if (err) {487		dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);488		goto err_put_clks;489	}490 491	ctrl->cmd = pmif_arb_cmd;492	ctrl->read_cmd = pmif_spmi_read_cmd;493	ctrl->write_cmd = pmif_spmi_write_cmd;494 495	chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;496	arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;497	arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset;498	arb->chan.rdata = PMIF_SWINF_0_RDATA_31_0 + chan_offset;499	arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;500	arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;501 502	raw_spin_lock_init(&arb->lock);503 504	platform_set_drvdata(pdev, ctrl);505 506	err = spmi_controller_add(ctrl);507	if (err)508		goto err_domain_remove;509 510	return 0;511 512err_domain_remove:513	clk_bulk_disable_unprepare(arb->nclks, arb->clks);514err_put_clks:515	clk_bulk_put(arb->nclks, arb->clks);516	return err;517}518 519static void mtk_spmi_remove(struct platform_device *pdev)520{521	struct spmi_controller *ctrl = platform_get_drvdata(pdev);522	struct pmif *arb = spmi_controller_get_drvdata(ctrl);523 524	spmi_controller_remove(ctrl);525	clk_bulk_disable_unprepare(arb->nclks, arb->clks);526	clk_bulk_put(arb->nclks, arb->clks);527}528 529static const struct of_device_id mtk_spmi_match_table[] = {530	{531		.compatible = "mediatek,mt6873-spmi",532		.data = &mt6873_pmif_arb,533	}, {534		.compatible = "mediatek,mt8195-spmi",535		.data = &mt8195_pmif_arb,536	}, {537		/* sentinel */538	},539};540MODULE_DEVICE_TABLE(of, mtk_spmi_match_table);541 542static struct platform_driver mtk_spmi_driver = {543	.driver		= {544		.name	= "spmi-mtk",545		.of_match_table = mtk_spmi_match_table,546	},547	.probe		= mtk_spmi_probe,548	.remove_new	= mtk_spmi_remove,549};550module_platform_driver(mtk_spmi_driver);551 552MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");553MODULE_DESCRIPTION("MediaTek SPMI Driver");554MODULE_LICENSE("GPL");555