1/* 2 * Driver for Amlogic Meson SPI flash controller (SPIFC) 3 * 4 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 * 10 * You should have received a copy of the GNU General Public License 11 * along with this program. If not, see <http://www.gnu.org/licenses/>. 12 */ 13 14#include <linux/clk.h> 15#include <linux/delay.h> 16#include <linux/device.h> 17#include <linux/io.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/of.h> 21#include <linux/platform_device.h> 22#include <linux/pm_runtime.h> 23#include <linux/regmap.h> 24#include <linux/spi/spi.h> 25#include <linux/types.h> 26 27/* register map */ 28#define REG_CMD 0x00 29#define REG_ADDR 0x04 30#define REG_CTRL 0x08 31#define REG_CTRL1 0x0c 32#define REG_STATUS 0x10 33#define REG_CTRL2 0x14 34#define REG_CLOCK 0x18 35#define REG_USER 0x1c 36#define REG_USER1 0x20 37#define REG_USER2 0x24 38#define REG_USER3 0x28 39#define REG_USER4 0x2c 40#define REG_SLAVE 0x30 41#define REG_SLAVE1 0x34 42#define REG_SLAVE2 0x38 43#define REG_SLAVE3 0x3c 44#define REG_C0 0x40 45#define REG_B8 0x60 46#define REG_MAX 0x7c 47 48/* register fields */ 49#define CMD_USER BIT(18) 50#define CTRL_ENABLE_AHB BIT(17) 51#define CLOCK_SOURCE BIT(31) 52#define CLOCK_DIV_SHIFT 12 53#define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT) 54#define CLOCK_CNT_HIGH_SHIFT 6 55#define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT) 56#define CLOCK_CNT_LOW_SHIFT 0 57#define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT) 58#define USER_DIN_EN_MS BIT(0) 59#define USER_CMP_MODE BIT(2) 60#define USER_UC_DOUT_SEL BIT(27) 61#define USER_UC_DIN_SEL BIT(28) 62#define USER_UC_MASK ((BIT(5) - 1) << 27) 63#define USER1_BN_UC_DOUT_SHIFT 17 64#define USER1_BN_UC_DOUT_MASK (0xff << 16) 65#define USER1_BN_UC_DIN_SHIFT 8 66#define USER1_BN_UC_DIN_MASK (0xff << 8) 67#define USER4_CS_ACT BIT(30) 68#define SLAVE_TRST_DONE BIT(4) 69#define SLAVE_OP_MODE BIT(30) 70#define SLAVE_SW_RST BIT(31) 71 72#define SPIFC_BUFFER_SIZE 64 73 74/** 75 * struct meson_spifc 76 * @master: the SPI master 77 * @regmap: regmap for device registers 78 * @clk: input clock of the built-in baud rate generator 79 * @device: the device structure 80 */ 81struct meson_spifc { 82 struct spi_master *master; 83 struct regmap *regmap; 84 struct clk *clk; 85 struct device *dev; 86}; 87 88static const struct regmap_config spifc_regmap_config = { 89 .reg_bits = 32, 90 .val_bits = 32, 91 .reg_stride = 4, 92 .max_register = REG_MAX, 93}; 94 95/** 96 * meson_spifc_wait_ready() - wait for the current operation to terminate 97 * @spifc: the Meson SPI device 98 * Return: 0 on success, a negative value on error 99 */ 100static int meson_spifc_wait_ready(struct meson_spifc *spifc) 101{ 102 unsigned long deadline = jiffies + msecs_to_jiffies(5); 103 u32 data; 104 105 do { 106 regmap_read(spifc->regmap, REG_SLAVE, &data); 107 if (data & SLAVE_TRST_DONE) 108 return 0; 109 cond_resched(); 110 } while (!time_after(jiffies, deadline)); 111 112 return -ETIMEDOUT; 113} 114 115/** 116 * meson_spifc_drain_buffer() - copy data from device buffer to memory 117 * @spifc: the Meson SPI device 118 * @buf: the destination buffer 119 * @len: number of bytes to copy 120 */ 121static void meson_spifc_drain_buffer(struct meson_spifc *spifc, u8 *buf, 122 int len) 123{ 124 u32 data; 125 int i = 0; 126 127 while (i < len) { 128 regmap_read(spifc->regmap, REG_C0 + i, &data); 129 130 if (len - i >= 4) { 131 *((u32 *)buf) = data; 132 buf += 4; 133 } else { 134 memcpy(buf, &data, len - i); 135 break; 136 } 137 i += 4; 138 } 139} 140 141/** 142 * meson_spifc_fill_buffer() - copy data from memory to device buffer 143 * @spifc: the Meson SPI device 144 * @buf: the source buffer 145 * @len: number of bytes to copy 146 */ 147static void meson_spifc_fill_buffer(struct meson_spifc *spifc, const u8 *buf, 148 int len) 149{ 150 u32 data; 151 int i = 0; 152 153 while (i < len) { 154 if (len - i >= 4) 155 data = *(u32 *)buf; 156 else 157 memcpy(&data, buf, len - i); 158 159 regmap_write(spifc->regmap, REG_C0 + i, data); 160 161 buf += 4; 162 i += 4; 163 } 164} 165 166/** 167 * meson_spifc_setup_speed() - program the clock divider 168 * @spifc: the Meson SPI device 169 * @speed: desired speed in Hz 170 */ 171static void meson_spifc_setup_speed(struct meson_spifc *spifc, u32 speed) 172{ 173 unsigned long parent, value; 174 int n; 175 176 parent = clk_get_rate(spifc->clk); 177 n = max_t(int, parent / speed - 1, 1); 178 179 dev_dbg(spifc->dev, "parent %lu, speed %u, n %d\n", parent, 180 speed, n); 181 182 value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK; 183 value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK; 184 value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & 185 CLOCK_CNT_HIGH_MASK; 186 187 regmap_write(spifc->regmap, REG_CLOCK, value); 188} 189 190/** 191 * meson_spifc_txrx() - transfer a chunk of data 192 * @spifc: the Meson SPI device 193 * @xfer: the current SPI transfer 194 * @offset: offset of the data to transfer 195 * @len: length of the data to transfer 196 * @last_xfer: whether this is the last transfer of the message 197 * @last_chunk: whether this is the last chunk of the transfer 198 * Return: 0 on success, a negative value on error 199 */ 200static int meson_spifc_txrx(struct meson_spifc *spifc, 201 struct spi_transfer *xfer, 202 int offset, int len, bool last_xfer, 203 bool last_chunk) 204{ 205 bool keep_cs = true; 206 int ret; 207 208 if (xfer->tx_buf) 209 meson_spifc_fill_buffer(spifc, xfer->tx_buf + offset, len); 210 211 /* enable DOUT stage */ 212 regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, 213 USER_UC_DOUT_SEL); 214 regmap_write(spifc->regmap, REG_USER1, 215 (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); 216 217 /* enable data input during DOUT */ 218 regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, 219 USER_DIN_EN_MS); 220 221 if (last_chunk) { 222 if (last_xfer) 223 keep_cs = xfer->cs_change; 224 else 225 keep_cs = !xfer->cs_change; 226 } 227 228 regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, 229 keep_cs ? USER4_CS_ACT : 0); 230 231 /* clear transition done bit */ 232 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); 233 /* start transfer */ 234 regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); 235 236 ret = meson_spifc_wait_ready(spifc); 237 238 if (!ret && xfer->rx_buf) 239 meson_spifc_drain_buffer(spifc, xfer->rx_buf + offset, len); 240 241 return ret; 242} 243 244/** 245 * meson_spifc_transfer_one() - perform a single transfer 246 * @master: the SPI master 247 * @spi: the SPI device 248 * @xfer: the current SPI transfer 249 * Return: 0 on success, a negative value on error 250 */ 251static int meson_spifc_transfer_one(struct spi_master *master, 252 struct spi_device *spi, 253 struct spi_transfer *xfer) 254{ 255 struct meson_spifc *spifc = spi_master_get_devdata(master); 256 int len, done = 0, ret = 0; 257 258 meson_spifc_setup_speed(spifc, xfer->speed_hz); 259 260 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); 261 262 while (done < xfer->len && !ret) { 263 len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE); 264 ret = meson_spifc_txrx(spifc, xfer, done, len, 265 spi_transfer_is_last(master, xfer), 266 done + len >= xfer->len); 267 done += len; 268 } 269 270 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 271 CTRL_ENABLE_AHB); 272 273 return ret; 274} 275 276/** 277 * meson_spifc_hw_init() - reset and initialize the SPI controller 278 * @spifc: the Meson SPI device 279 */ 280static void meson_spifc_hw_init(struct meson_spifc *spifc) 281{ 282 /* reset device */ 283 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, 284 SLAVE_SW_RST); 285 /* disable compatible mode */ 286 regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); 287 /* set master mode */ 288 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); 289} 290 291static int meson_spifc_probe(struct platform_device *pdev) 292{ 293 struct spi_master *master; 294 struct meson_spifc *spifc; 295 struct resource *res; 296 void __iomem *base; 297 unsigned int rate; 298 int ret = 0; 299 300 master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc)); 301 if (!master) 302 return -ENOMEM; 303 304 platform_set_drvdata(pdev, master); 305 306 spifc = spi_master_get_devdata(master); 307 spifc->dev = &pdev->dev; 308 309 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 310 base = devm_ioremap_resource(spifc->dev, res); 311 if (IS_ERR(base)) { 312 ret = PTR_ERR(base); 313 goto out_err; 314 } 315 316 spifc->regmap = devm_regmap_init_mmio(spifc->dev, base, 317 &spifc_regmap_config); 318 if (IS_ERR(spifc->regmap)) { 319 ret = PTR_ERR(spifc->regmap); 320 goto out_err; 321 } 322 323 spifc->clk = devm_clk_get(spifc->dev, NULL); 324 if (IS_ERR(spifc->clk)) { 325 dev_err(spifc->dev, "missing clock\n"); 326 ret = PTR_ERR(spifc->clk); 327 goto out_err; 328 } 329 330 ret = clk_prepare_enable(spifc->clk); 331 if (ret) { 332 dev_err(spifc->dev, "can't prepare clock\n"); 333 goto out_err; 334 } 335 336 rate = clk_get_rate(spifc->clk); 337 338 master->num_chipselect = 1; 339 master->dev.of_node = pdev->dev.of_node; 340 master->bits_per_word_mask = SPI_BPW_MASK(8); 341 master->auto_runtime_pm = true; 342 master->transfer_one = meson_spifc_transfer_one; 343 master->min_speed_hz = rate >> 6; 344 master->max_speed_hz = rate >> 1; 345 346 meson_spifc_hw_init(spifc); 347 348 pm_runtime_set_active(spifc->dev); 349 pm_runtime_enable(spifc->dev); 350 351 ret = devm_spi_register_master(spifc->dev, master); 352 if (ret) { 353 dev_err(spifc->dev, "failed to register spi master\n"); 354 goto out_clk; 355 } 356 357 return 0; 358out_clk: 359 clk_disable_unprepare(spifc->clk); 360out_err: 361 spi_master_put(master); 362 return ret; 363} 364 365static int meson_spifc_remove(struct platform_device *pdev) 366{ 367 struct spi_master *master = platform_get_drvdata(pdev); 368 struct meson_spifc *spifc = spi_master_get_devdata(master); 369 370 pm_runtime_get_sync(&pdev->dev); 371 clk_disable_unprepare(spifc->clk); 372 pm_runtime_disable(&pdev->dev); 373 374 return 0; 375} 376 377#ifdef CONFIG_PM_SLEEP 378static int meson_spifc_suspend(struct device *dev) 379{ 380 struct spi_master *master = dev_get_drvdata(dev); 381 struct meson_spifc *spifc = spi_master_get_devdata(master); 382 int ret; 383 384 ret = spi_master_suspend(master); 385 if (ret) 386 return ret; 387 388 if (!pm_runtime_suspended(dev)) 389 clk_disable_unprepare(spifc->clk); 390 391 return 0; 392} 393 394static int meson_spifc_resume(struct device *dev) 395{ 396 struct spi_master *master = dev_get_drvdata(dev); 397 struct meson_spifc *spifc = spi_master_get_devdata(master); 398 int ret; 399 400 if (!pm_runtime_suspended(dev)) { 401 ret = clk_prepare_enable(spifc->clk); 402 if (ret) 403 return ret; 404 } 405 406 meson_spifc_hw_init(spifc); 407 408 ret = spi_master_resume(master); 409 if (ret) 410 clk_disable_unprepare(spifc->clk); 411 412 return ret; 413} 414#endif /* CONFIG_PM_SLEEP */ 415 416#ifdef CONFIG_PM 417static int meson_spifc_runtime_suspend(struct device *dev) 418{ 419 struct spi_master *master = dev_get_drvdata(dev); 420 struct meson_spifc *spifc = spi_master_get_devdata(master); 421 422 clk_disable_unprepare(spifc->clk); 423 424 return 0; 425} 426 427static int meson_spifc_runtime_resume(struct device *dev) 428{ 429 struct spi_master *master = dev_get_drvdata(dev); 430 struct meson_spifc *spifc = spi_master_get_devdata(master); 431 432 return clk_prepare_enable(spifc->clk); 433} 434#endif /* CONFIG_PM */ 435 436static const struct dev_pm_ops meson_spifc_pm_ops = { 437 SET_SYSTEM_SLEEP_PM_OPS(meson_spifc_suspend, meson_spifc_resume) 438 SET_RUNTIME_PM_OPS(meson_spifc_runtime_suspend, 439 meson_spifc_runtime_resume, 440 NULL) 441}; 442 443static const struct of_device_id meson_spifc_dt_match[] = { 444 { .compatible = "amlogic,meson6-spifc", }, 445 { }, 446}; 447 448static struct platform_driver meson_spifc_driver = { 449 .probe = meson_spifc_probe, 450 .remove = meson_spifc_remove, 451 .driver = { 452 .name = "meson-spifc", 453 .of_match_table = of_match_ptr(meson_spifc_dt_match), 454 .pm = &meson_spifc_pm_ops, 455 }, 456}; 457 458module_platform_driver(meson_spifc_driver); 459 460MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); 461MODULE_DESCRIPTION("Amlogic Meson SPIFC driver"); 462MODULE_LICENSE("GPL v2"); 463