brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · 3aff5a1 Raw
321 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Copyright (C) 2022 Hewlett-Packard Development Company, L.P. */3 4#include <linux/iopoll.h>5#include <linux/of.h>6#include <linux/platform_device.h>7#include <linux/spi/spi.h>8#include <linux/spi/spi-mem.h>9 10#define GXP_SPI0_MAX_CHIPSELECT	211#define GXP_SPI_SLEEP_TIME	112#define GXP_SPI_TIMEOUT (130 * 1000000 / GXP_SPI_SLEEP_TIME)13 14#define MANUAL_MODE		015#define DIRECT_MODE		116#define SPILDAT_LEN		25617 18#define OFFSET_SPIMCFG		0x019#define OFFSET_SPIMCTRL		0x420#define OFFSET_SPICMD		0x521#define OFFSET_SPIDCNT		0x622#define OFFSET_SPIADDR		0x823#define OFFSET_SPIINTSTS	0xc24 25#define SPIMCTRL_START		0x0126#define SPIMCTRL_BUSY		0x0227#define SPIMCTRL_DIR		0x0828 29struct gxp_spi;30 31struct gxp_spi_chip {32	struct gxp_spi *spifi;33	u32 cs;34};35 36struct gxp_spi_data {37	u32 max_cs;38	u32 mode_bits;39};40 41struct gxp_spi {42	const struct gxp_spi_data *data;43	void __iomem *reg_base;44	void __iomem *dat_base;45	void __iomem *dir_base;46	struct device *dev;47	struct gxp_spi_chip chips[GXP_SPI0_MAX_CHIPSELECT];48};49 50static void gxp_spi_set_mode(struct gxp_spi *spifi, int mode)51{52	u8 value;53	void __iomem *reg_base = spifi->reg_base;54 55	value = readb(reg_base + OFFSET_SPIMCTRL);56 57	if (mode == MANUAL_MODE) {58		writeb(0x55, reg_base + OFFSET_SPICMD);59		writeb(0xaa, reg_base + OFFSET_SPICMD);60		value &= ~0x30;61	} else {62		value |= 0x30;63	}64	writeb(value, reg_base + OFFSET_SPIMCTRL);65}66 67static int gxp_spi_read_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)68{69	int ret;70	struct gxp_spi *spifi = chip->spifi;71	void __iomem *reg_base = spifi->reg_base;72	u32 value;73 74	value = readl(reg_base + OFFSET_SPIMCFG);75	value &= ~(1 << 24);76	value |= (chip->cs << 24);77	value &= ~(0x07 << 16);78	value &= ~(0x1f << 19);79	writel(value, reg_base + OFFSET_SPIMCFG);80 81	writel(0, reg_base + OFFSET_SPIADDR);82 83	writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);84 85	writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);86 87	value = readb(reg_base + OFFSET_SPIMCTRL);88	value &= ~SPIMCTRL_DIR;89	value |= SPIMCTRL_START;90 91	writeb(value, reg_base + OFFSET_SPIMCTRL);92 93	ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,94				 !(value & SPIMCTRL_BUSY),95				 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);96	if (ret) {97		dev_warn(spifi->dev, "read reg busy time out\n");98		return ret;99	}100 101	memcpy_fromio(op->data.buf.in, spifi->dat_base, op->data.nbytes);102	return ret;103}104 105static int gxp_spi_write_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)106{107	int ret;108	struct gxp_spi *spifi = chip->spifi;109	void __iomem *reg_base = spifi->reg_base;110	u32 value;111 112	value = readl(reg_base + OFFSET_SPIMCFG);113	value &= ~(1 << 24);114	value |= (chip->cs << 24);115	value &= ~(0x07 << 16);116	value &= ~(0x1f << 19);117	writel(value, reg_base + OFFSET_SPIMCFG);118 119	writel(0, reg_base + OFFSET_SPIADDR);120 121	writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);122 123	memcpy_toio(spifi->dat_base, op->data.buf.in, op->data.nbytes);124 125	writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);126 127	value = readb(reg_base + OFFSET_SPIMCTRL);128	value |= SPIMCTRL_DIR;129	value |= SPIMCTRL_START;130 131	writeb(value, reg_base + OFFSET_SPIMCTRL);132 133	ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,134				 !(value & SPIMCTRL_BUSY),135				 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);136	if (ret)137		dev_warn(spifi->dev, "write reg busy time out\n");138 139	return ret;140}141 142static ssize_t gxp_spi_read(struct gxp_spi_chip *chip, const struct spi_mem_op *op)143{144	struct gxp_spi *spifi = chip->spifi;145	u32 offset = op->addr.val;146 147	if (chip->cs == 0)148		offset += 0x4000000;149 150	memcpy_fromio(op->data.buf.in, spifi->dir_base + offset, op->data.nbytes);151 152	return 0;153}154 155static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op *op)156{157	struct gxp_spi *spifi = chip->spifi;158	void __iomem *reg_base = spifi->reg_base;159	u32 write_len;160	u32 value;161	int ret;162 163	write_len = op->data.nbytes;164	if (write_len > SPILDAT_LEN)165		write_len = SPILDAT_LEN;166 167	value = readl(reg_base + OFFSET_SPIMCFG);168	value &= ~(1 << 24);169	value |= (chip->cs << 24);170	value &= ~(0x07 << 16);171	value |= (op->addr.nbytes << 16);172	value &= ~(0x1f << 19);173	writel(value, reg_base + OFFSET_SPIMCFG);174 175	writel(op->addr.val, reg_base + OFFSET_SPIADDR);176 177	writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);178 179	writew(write_len, reg_base + OFFSET_SPIDCNT);180 181	memcpy_toio(spifi->dat_base, op->data.buf.in, write_len);182 183	value = readb(reg_base + OFFSET_SPIMCTRL);184	value |= SPIMCTRL_DIR;185	value |= SPIMCTRL_START;186 187	writeb(value, reg_base + OFFSET_SPIMCTRL);188 189	ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,190				 !(value & SPIMCTRL_BUSY),191				 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);192	if (ret) {193		dev_warn(spifi->dev, "write busy time out\n");194		return ret;195	}196 197	return 0;198}199 200static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)201{202	struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->controller);203	struct gxp_spi_chip *chip = &spifi->chips[spi_get_chipselect(mem->spi, 0)];204	int ret;205 206	if (op->data.dir == SPI_MEM_DATA_IN) {207		if (!op->addr.nbytes)208			ret = gxp_spi_read_reg(chip, op);209		else210			ret = gxp_spi_read(chip, op);211	} else {212		if (!op->addr.nbytes)213			ret = gxp_spi_write_reg(chip, op);214		else215			ret = gxp_spi_write(chip, op);216	}217 218	return ret;219}220 221static int gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)222{223	int ret;224 225	ret = do_gxp_exec_mem_op(mem, op);226	if (ret)227		dev_err(&mem->spi->dev, "operation failed: %d", ret);228 229	return ret;230}231 232static const struct spi_controller_mem_ops gxp_spi_mem_ops = {233	.exec_op = gxp_exec_mem_op,234};235 236static int gxp_spi_setup(struct spi_device *spi)237{238	struct gxp_spi *spifi = spi_controller_get_devdata(spi->controller);239	unsigned int cs = spi_get_chipselect(spi, 0);240	struct gxp_spi_chip *chip = &spifi->chips[cs];241 242	chip->spifi = spifi;243	chip->cs = cs;244 245	gxp_spi_set_mode(spifi, MANUAL_MODE);246 247	return 0;248}249 250static int gxp_spifi_probe(struct platform_device *pdev)251{252	struct device *dev = &pdev->dev;253	const struct gxp_spi_data *data;254	struct spi_controller *ctlr;255	struct gxp_spi *spifi;256	int ret;257 258	data = of_device_get_match_data(&pdev->dev);259 260	ctlr = devm_spi_alloc_host(dev, sizeof(*spifi));261	if (!ctlr)262		return -ENOMEM;263 264	spifi = spi_controller_get_devdata(ctlr);265 266	platform_set_drvdata(pdev, spifi);267	spifi->data = data;268	spifi->dev = dev;269 270	spifi->reg_base = devm_platform_ioremap_resource(pdev, 0);271	if (IS_ERR(spifi->reg_base))272		return PTR_ERR(spifi->reg_base);273 274	spifi->dat_base = devm_platform_ioremap_resource(pdev, 1);275	if (IS_ERR(spifi->dat_base))276		return PTR_ERR(spifi->dat_base);277 278	spifi->dir_base = devm_platform_ioremap_resource(pdev, 2);279	if (IS_ERR(spifi->dir_base))280		return PTR_ERR(spifi->dir_base);281 282	ctlr->mode_bits = data->mode_bits;283	ctlr->bus_num = pdev->id;284	ctlr->mem_ops = &gxp_spi_mem_ops;285	ctlr->setup = gxp_spi_setup;286	ctlr->num_chipselect = data->max_cs;287	ctlr->dev.of_node = dev->of_node;288 289	ret = devm_spi_register_controller(dev, ctlr);290	if (ret) {291		return dev_err_probe(&pdev->dev, ret,292				     "failed to register spi controller\n");293	}294 295	return 0;296}297 298static const struct gxp_spi_data gxp_spifi_data = {299	.max_cs	= 2,300	.mode_bits = 0,301};302 303static const struct of_device_id gxp_spifi_match[] = {304	{.compatible = "hpe,gxp-spifi", .data = &gxp_spifi_data },305	{ /* null */ }306};307MODULE_DEVICE_TABLE(of, gxp_spifi_match);308 309static struct platform_driver gxp_spifi_driver = {310	.probe = gxp_spifi_probe,311	.driver = {312		.name = "gxp-spifi",313		.of_match_table = gxp_spifi_match,314	},315};316module_platform_driver(gxp_spifi_driver);317 318MODULE_DESCRIPTION("HPE GXP SPI Flash Interface driver");319MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");320MODULE_LICENSE("GPL");321