1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Altera SPI driver 4 * 5 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw> 6 * 7 * Based on spi_s3c24xx.c, which is: 8 * Copyright (c) 2006 Ben Dooks 9 * Copyright (c) 2006 Simtec Electronics 10 * Ben Dooks <ben@simtec.co.uk> 11 */ 12 13#include <linux/interrupt.h> 14#include <linux/errno.h> 15#include <linux/module.h> 16#include <linux/platform_device.h> 17#include <linux/spi/altera.h> 18#include <linux/spi/spi.h> 19#include <linux/io.h> 20#include <linux/of.h> 21 22#define DRV_NAME "spi_altera" 23 24#define ALTERA_SPI_RXDATA 0 25#define ALTERA_SPI_TXDATA 4 26#define ALTERA_SPI_STATUS 8 27#define ALTERA_SPI_CONTROL 12 28#define ALTERA_SPI_SLAVE_SEL 20 29 30#define ALTERA_SPI_STATUS_ROE_MSK 0x8 31#define ALTERA_SPI_STATUS_TOE_MSK 0x10 32#define ALTERA_SPI_STATUS_TMT_MSK 0x20 33#define ALTERA_SPI_STATUS_TRDY_MSK 0x40 34#define ALTERA_SPI_STATUS_RRDY_MSK 0x80 35#define ALTERA_SPI_STATUS_E_MSK 0x100 36 37#define ALTERA_SPI_CONTROL_IROE_MSK 0x8 38#define ALTERA_SPI_CONTROL_ITOE_MSK 0x10 39#define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40 40#define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80 41#define ALTERA_SPI_CONTROL_IE_MSK 0x100 42#define ALTERA_SPI_CONTROL_SSO_MSK 0x400 43 44#define ALTERA_SPI_MAX_CS 32 45 46enum altera_spi_type { 47 ALTERA_SPI_TYPE_UNKNOWN, 48 ALTERA_SPI_TYPE_SUBDEV, 49}; 50 51struct altera_spi { 52 int irq; 53 int len; 54 int count; 55 int bytes_per_word; 56 u32 imr; 57 58 /* data buffers */ 59 const unsigned char *tx; 60 unsigned char *rx; 61 62 struct regmap *regmap; 63 u32 regoff; 64 struct device *dev; 65}; 66 67static const struct regmap_config spi_altera_config = { 68 .reg_bits = 32, 69 .reg_stride = 4, 70 .val_bits = 32, 71 .fast_io = true, 72}; 73 74static int altr_spi_writel(struct altera_spi *hw, unsigned int reg, 75 unsigned int val) 76{ 77 int ret; 78 79 ret = regmap_write(hw->regmap, hw->regoff + reg, val); 80 if (ret) 81 dev_err(hw->dev, "fail to write reg 0x%x val 0x%x: %d\n", 82 reg, val, ret); 83 84 return ret; 85} 86 87static int altr_spi_readl(struct altera_spi *hw, unsigned int reg, 88 unsigned int *val) 89{ 90 int ret; 91 92 ret = regmap_read(hw->regmap, hw->regoff + reg, val); 93 if (ret) 94 dev_err(hw->dev, "fail to read reg 0x%x: %d\n", reg, ret); 95 96 return ret; 97} 98 99static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev) 100{ 101 return spi_master_get_devdata(sdev->master); 102} 103 104static void altera_spi_set_cs(struct spi_device *spi, bool is_high) 105{ 106 struct altera_spi *hw = altera_spi_to_hw(spi); 107 108 if (is_high) { 109 hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; 110 altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); 111 altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0); 112 } else { 113 altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 114 BIT(spi->chip_select)); 115 hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; 116 altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); 117 } 118} 119 120static void altera_spi_tx_word(struct altera_spi *hw) 121{ 122 unsigned int txd = 0; 123 124 if (hw->tx) { 125 switch (hw->bytes_per_word) { 126 case 1: 127 txd = hw->tx[hw->count]; 128 break; 129 case 2: 130 txd = (hw->tx[hw->count * 2] 131 | (hw->tx[hw->count * 2 + 1] << 8)); 132 break; 133 case 4: 134 txd = (hw->tx[hw->count * 4] 135 | (hw->tx[hw->count * 4 + 1] << 8) 136 | (hw->tx[hw->count * 4 + 2] << 16) 137 | (hw->tx[hw->count * 4 + 3] << 24)); 138 break; 139 140 } 141 } 142 143 altr_spi_writel(hw, ALTERA_SPI_TXDATA, txd); 144} 145 146static void altera_spi_rx_word(struct altera_spi *hw) 147{ 148 unsigned int rxd; 149 150 altr_spi_readl(hw, ALTERA_SPI_RXDATA, &rxd); 151 if (hw->rx) { 152 switch (hw->bytes_per_word) { 153 case 1: 154 hw->rx[hw->count] = rxd; 155 break; 156 case 2: 157 hw->rx[hw->count * 2] = rxd; 158 hw->rx[hw->count * 2 + 1] = rxd >> 8; 159 break; 160 case 4: 161 hw->rx[hw->count * 4] = rxd; 162 hw->rx[hw->count * 4 + 1] = rxd >> 8; 163 hw->rx[hw->count * 4 + 2] = rxd >> 16; 164 hw->rx[hw->count * 4 + 3] = rxd >> 24; 165 break; 166 167 } 168 } 169 170 hw->count++; 171} 172 173static int altera_spi_txrx(struct spi_master *master, 174 struct spi_device *spi, struct spi_transfer *t) 175{ 176 struct altera_spi *hw = spi_master_get_devdata(master); 177 u32 val; 178 179 hw->tx = t->tx_buf; 180 hw->rx = t->rx_buf; 181 hw->count = 0; 182 hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8); 183 hw->len = t->len / hw->bytes_per_word; 184 185 if (hw->irq >= 0) { 186 /* enable receive interrupt */ 187 hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK; 188 altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); 189 190 /* send the first byte */ 191 altera_spi_tx_word(hw); 192 193 return 1; 194 } 195 196 while (hw->count < hw->len) { 197 altera_spi_tx_word(hw); 198 199 for (;;) { 200 altr_spi_readl(hw, ALTERA_SPI_STATUS, &val); 201 if (val & ALTERA_SPI_STATUS_RRDY_MSK) 202 break; 203 204 cpu_relax(); 205 } 206 207 altera_spi_rx_word(hw); 208 } 209 spi_finalize_current_transfer(master); 210 211 return 0; 212} 213 214static irqreturn_t altera_spi_irq(int irq, void *dev) 215{ 216 struct spi_master *master = dev; 217 struct altera_spi *hw = spi_master_get_devdata(master); 218 219 altera_spi_rx_word(hw); 220 221 if (hw->count < hw->len) { 222 altera_spi_tx_word(hw); 223 } else { 224 /* disable receive interrupt */ 225 hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; 226 altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); 227 228 spi_finalize_current_transfer(master); 229 } 230 231 return IRQ_HANDLED; 232} 233 234static int altera_spi_probe(struct platform_device *pdev) 235{ 236 const struct platform_device_id *platid = platform_get_device_id(pdev); 237 struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev); 238 enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN; 239 struct altera_spi *hw; 240 struct spi_master *master; 241 int err = -ENODEV; 242 u32 val; 243 u16 i; 244 245 master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi)); 246 if (!master) 247 return err; 248 249 /* setup the master state. */ 250 master->bus_num = pdev->id; 251 252 if (pdata) { 253 if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) { 254 dev_err(&pdev->dev, 255 "Invalid number of chipselect: %hu\n", 256 pdata->num_chipselect); 257 err = -EINVAL; 258 goto exit; 259 } 260 261 master->num_chipselect = pdata->num_chipselect; 262 master->mode_bits = pdata->mode_bits; 263 master->bits_per_word_mask = pdata->bits_per_word_mask; 264 } else { 265 master->num_chipselect = 16; 266 master->mode_bits = SPI_CS_HIGH; 267 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); 268 } 269 270 master->dev.of_node = pdev->dev.of_node; 271 master->transfer_one = altera_spi_txrx; 272 master->set_cs = altera_spi_set_cs; 273 274 hw = spi_master_get_devdata(master); 275 hw->dev = &pdev->dev; 276 277 if (platid) 278 type = platid->driver_data; 279 280 /* find and map our resources */ 281 if (type == ALTERA_SPI_TYPE_SUBDEV) { 282 struct resource *regoff; 283 284 hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); 285 if (!hw->regmap) { 286 dev_err(&pdev->dev, "get regmap failed\n"); 287 goto exit; 288 } 289 290 regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); 291 if (regoff) 292 hw->regoff = regoff->start; 293 } else { 294 void __iomem *res; 295 296 res = devm_platform_ioremap_resource(pdev, 0); 297 if (IS_ERR(res)) { 298 err = PTR_ERR(res); 299 goto exit; 300 } 301 302 hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, 303 &spi_altera_config); 304 if (IS_ERR(hw->regmap)) { 305 dev_err(&pdev->dev, "regmap mmio init failed\n"); 306 err = PTR_ERR(hw->regmap); 307 goto exit; 308 } 309 } 310 311 /* program defaults into the registers */ 312 hw->imr = 0; /* disable spi interrupts */ 313 altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); 314 altr_spi_writel(hw, ALTERA_SPI_STATUS, 0); /* clear status reg */ 315 altr_spi_readl(hw, ALTERA_SPI_STATUS, &val); 316 if (val & ALTERA_SPI_STATUS_RRDY_MSK) 317 altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */ 318 /* irq is optional */ 319 hw->irq = platform_get_irq(pdev, 0); 320 if (hw->irq >= 0) { 321 err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0, 322 pdev->name, master); 323 if (err) 324 goto exit; 325 } 326 327 err = devm_spi_register_master(&pdev->dev, master); 328 if (err) 329 goto exit; 330 331 if (pdata) { 332 for (i = 0; i < pdata->num_devices; i++) { 333 if (!spi_new_device(master, pdata->devices + i)) 334 dev_warn(&pdev->dev, 335 "unable to create SPI device: %s\n", 336 pdata->devices[i].modalias); 337 } 338 } 339 340 dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq); 341 342 return 0; 343exit: 344 spi_master_put(master); 345 return err; 346} 347 348#ifdef CONFIG_OF 349static const struct of_device_id altera_spi_match[] = { 350 { .compatible = "ALTR,spi-1.0", }, 351 { .compatible = "altr,spi-1.0", }, 352 {}, 353}; 354MODULE_DEVICE_TABLE(of, altera_spi_match); 355#endif /* CONFIG_OF */ 356 357static const struct platform_device_id altera_spi_ids[] = { 358 { DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN }, 359 { "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV }, 360 { } 361}; 362MODULE_DEVICE_TABLE(platform, altera_spi_ids); 363 364static struct platform_driver altera_spi_driver = { 365 .probe = altera_spi_probe, 366 .driver = { 367 .name = DRV_NAME, 368 .pm = NULL, 369 .of_match_table = of_match_ptr(altera_spi_match), 370 }, 371 .id_table = altera_spi_ids, 372}; 373module_platform_driver(altera_spi_driver); 374 375MODULE_DESCRIPTION("Altera SPI driver"); 376MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); 377MODULE_LICENSE("GPL"); 378MODULE_ALIAS("platform:" DRV_NAME); 379