brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 5d63aa1 Raw
308 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * SuperH HSPI bus driver4 *5 * Copyright (C) 2011  Kuninori Morimoto6 *7 * Based on spi-sh.c:8 * Based on pxa2xx_spi.c:9 * Copyright (C) 2011 Renesas Solutions Corp.10 * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs11 */12 13#include <linux/clk.h>14#include <linux/module.h>15#include <linux/kernel.h>16#include <linux/timer.h>17#include <linux/delay.h>18#include <linux/list.h>19#include <linux/interrupt.h>20#include <linux/platform_device.h>21#include <linux/pm_runtime.h>22#include <linux/io.h>23#include <linux/spi/spi.h>24#include <linux/spi/sh_hspi.h>25 26#define SPCR	0x0027#define SPSR	0x0428#define SPSCR	0x0829#define SPTBR	0x0C30#define SPRBR	0x1031#define SPCR2	0x1432 33/* SPSR */34#define RXFL	(1 << 2)35 36struct hspi_priv {37	void __iomem *addr;38	struct spi_controller *ctlr;39	struct device *dev;40	struct clk *clk;41};42 43/*44 *		basic function45 */46static void hspi_write(struct hspi_priv *hspi, int reg, u32 val)47{48	iowrite32(val, hspi->addr + reg);49}50 51static u32 hspi_read(struct hspi_priv *hspi, int reg)52{53	return ioread32(hspi->addr + reg);54}55 56static void hspi_bit_set(struct hspi_priv *hspi, int reg, u32 mask, u32 set)57{58	u32 val = hspi_read(hspi, reg);59 60	val &= ~mask;61	val |= set & mask;62 63	hspi_write(hspi, reg, val);64}65 66/*67 *		transfer function68 */69static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)70{71	int t = 256;72 73	while (t--) {74		if ((mask & hspi_read(hspi, SPSR)) == val)75			return 0;76 77		udelay(10);78	}79 80	dev_err(hspi->dev, "timeout\n");81	return -ETIMEDOUT;82}83 84/*85 *		spi host function86 */87 88#define hspi_hw_cs_enable(hspi)		hspi_hw_cs_ctrl(hspi, 0)89#define hspi_hw_cs_disable(hspi)	hspi_hw_cs_ctrl(hspi, 1)90static void hspi_hw_cs_ctrl(struct hspi_priv *hspi, int hi)91{92	hspi_bit_set(hspi, SPSCR, (1 << 6), (hi) << 6);93}94 95static void hspi_hw_setup(struct hspi_priv *hspi,96			  struct spi_message *msg,97			  struct spi_transfer *t)98{99	struct spi_device *spi = msg->spi;100	struct device *dev = hspi->dev;101	u32 spcr, idiv_clk;102	u32 rate, best_rate, min, tmp;103 104	/*105	 * find best IDIV/CLKCx settings106	 */107	min = ~0;108	best_rate = 0;109	spcr = 0;110	for (idiv_clk = 0x00; idiv_clk <= 0x3F; idiv_clk++) {111		rate = clk_get_rate(hspi->clk);112 113		/* IDIV calculation */114		if (idiv_clk & (1 << 5))115			rate /= 128;116		else117			rate /= 16;118 119		/* CLKCx calculation */120		rate /= (((idiv_clk & 0x1F) + 1) * 2);121 122		/* save best settings */123		tmp = abs(t->speed_hz - rate);124		if (tmp < min) {125			min = tmp;126			spcr = idiv_clk;127			best_rate = rate;128		}129	}130 131	if (spi->mode & SPI_CPHA)132		spcr |= 1 << 7;133	if (spi->mode & SPI_CPOL)134		spcr |= 1 << 6;135 136	dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);137 138	hspi_write(hspi, SPCR, spcr);139	hspi_write(hspi, SPSR, 0x0);140	hspi_write(hspi, SPSCR, 0x21);	/* master mode / CS control */141}142 143static int hspi_transfer_one_message(struct spi_controller *ctlr,144				     struct spi_message *msg)145{146	struct hspi_priv *hspi = spi_controller_get_devdata(ctlr);147	struct spi_transfer *t;148	u32 tx;149	u32 rx;150	int ret, i;151	unsigned int cs_change;152	const int nsecs = 50;153 154	dev_dbg(hspi->dev, "%s\n", __func__);155 156	cs_change = 1;157	ret = 0;158	list_for_each_entry(t, &msg->transfers, transfer_list) {159 160		if (cs_change) {161			hspi_hw_setup(hspi, msg, t);162			hspi_hw_cs_enable(hspi);163			ndelay(nsecs);164		}165		cs_change = t->cs_change;166 167		for (i = 0; i < t->len; i++) {168 169			/* wait remains */170			ret = hspi_status_check_timeout(hspi, 0x1, 0);171			if (ret < 0)172				break;173 174			tx = 0;175			if (t->tx_buf)176				tx = (u32)((u8 *)t->tx_buf)[i];177 178			hspi_write(hspi, SPTBR, tx);179 180			/* wait receive */181			ret = hspi_status_check_timeout(hspi, 0x4, 0x4);182			if (ret < 0)183				break;184 185			rx = hspi_read(hspi, SPRBR);186			if (t->rx_buf)187				((u8 *)t->rx_buf)[i] = (u8)rx;188 189		}190 191		msg->actual_length += t->len;192 193		spi_transfer_delay_exec(t);194 195		if (cs_change) {196			ndelay(nsecs);197			hspi_hw_cs_disable(hspi);198			ndelay(nsecs);199		}200	}201 202	msg->status = ret;203	if (!cs_change) {204		ndelay(nsecs);205		hspi_hw_cs_disable(hspi);206	}207	spi_finalize_current_message(ctlr);208 209	return ret;210}211 212static int hspi_probe(struct platform_device *pdev)213{214	struct resource *res;215	struct spi_controller *ctlr;216	struct hspi_priv *hspi;217	struct clk *clk;218	int ret;219 220	/* get base addr */221	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);222	if (!res) {223		dev_err(&pdev->dev, "invalid resource\n");224		return -EINVAL;225	}226 227	ctlr = spi_alloc_host(&pdev->dev, sizeof(*hspi));228	if (!ctlr)229		return -ENOMEM;230 231	clk = clk_get(&pdev->dev, NULL);232	if (IS_ERR(clk)) {233		dev_err(&pdev->dev, "couldn't get clock\n");234		ret = -EINVAL;235		goto error0;236	}237 238	hspi = spi_controller_get_devdata(ctlr);239	platform_set_drvdata(pdev, hspi);240 241	/* init hspi */242	hspi->ctlr	= ctlr;243	hspi->dev	= &pdev->dev;244	hspi->clk	= clk;245	hspi->addr	= devm_ioremap(hspi->dev,246				       res->start, resource_size(res));247	if (!hspi->addr) {248		ret = -ENOMEM;249		goto error1;250	}251 252	pm_runtime_enable(&pdev->dev);253 254	ctlr->bus_num = pdev->id;255	ctlr->mode_bits	= SPI_CPOL | SPI_CPHA;256	ctlr->dev.of_node = pdev->dev.of_node;257	ctlr->auto_runtime_pm = true;258	ctlr->transfer_one_message = hspi_transfer_one_message;259	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);260 261	ret = devm_spi_register_controller(&pdev->dev, ctlr);262	if (ret < 0) {263		dev_err(&pdev->dev, "devm_spi_register_controller error.\n");264		goto error2;265	}266 267	return 0;268 269 error2:270	pm_runtime_disable(&pdev->dev);271 error1:272	clk_put(clk);273 error0:274	spi_controller_put(ctlr);275 276	return ret;277}278 279static void hspi_remove(struct platform_device *pdev)280{281	struct hspi_priv *hspi = platform_get_drvdata(pdev);282 283	pm_runtime_disable(&pdev->dev);284 285	clk_put(hspi->clk);286}287 288static const struct of_device_id hspi_of_match[] = {289	{ .compatible = "renesas,hspi", },290	{ /* sentinel */ }291};292MODULE_DEVICE_TABLE(of, hspi_of_match);293 294static struct platform_driver hspi_driver = {295	.probe = hspi_probe,296	.remove_new = hspi_remove,297	.driver = {298		.name = "sh-hspi",299		.of_match_table = hspi_of_match,300	},301};302module_platform_driver(hspi_driver);303 304MODULE_DESCRIPTION("SuperH HSPI bus driver");305MODULE_LICENSE("GPL v2");306MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");307MODULE_ALIAS("platform:sh-hspi");308