spi-altera-platform.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Altera SPI driver
  4. *
  5. * Copyright (C) 2008 Thomas Chou <[email protected]>
  6. *
  7. * Based on spi_s3c24xx.c, which is:
  8. * Copyright (c) 2006 Ben Dooks
  9. * Copyright (c) 2006 Simtec Electronics
  10. * Ben Dooks <[email protected]>
  11. */
  12. #include <linux/interrupt.h>
  13. #include <linux/errno.h>
  14. #include <linux/module.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/spi/altera.h>
  17. #include <linux/spi/spi.h>
  18. #include <linux/io.h>
  19. #include <linux/of.h>
  20. #define DRV_NAME "spi_altera"
  21. enum altera_spi_type {
  22. ALTERA_SPI_TYPE_UNKNOWN,
  23. ALTERA_SPI_TYPE_SUBDEV,
  24. };
  25. static const struct regmap_config spi_altera_config = {
  26. .reg_bits = 32,
  27. .reg_stride = 4,
  28. .val_bits = 32,
  29. .fast_io = true,
  30. };
  31. static int altera_spi_probe(struct platform_device *pdev)
  32. {
  33. const struct platform_device_id *platid = platform_get_device_id(pdev);
  34. struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev);
  35. enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN;
  36. struct altera_spi *hw;
  37. struct spi_master *master;
  38. int err = -ENODEV;
  39. u16 i;
  40. master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
  41. if (!master)
  42. return err;
  43. /* setup the master state. */
  44. master->bus_num = -1;
  45. if (pdata) {
  46. if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) {
  47. dev_err(&pdev->dev,
  48. "Invalid number of chipselect: %u\n",
  49. pdata->num_chipselect);
  50. err = -EINVAL;
  51. goto exit;
  52. }
  53. master->num_chipselect = pdata->num_chipselect;
  54. master->mode_bits = pdata->mode_bits;
  55. master->bits_per_word_mask = pdata->bits_per_word_mask;
  56. } else {
  57. master->num_chipselect = 16;
  58. master->mode_bits = SPI_CS_HIGH;
  59. master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
  60. }
  61. master->dev.of_node = pdev->dev.of_node;
  62. hw = spi_master_get_devdata(master);
  63. hw->dev = &pdev->dev;
  64. if (platid)
  65. type = platid->driver_data;
  66. /* find and map our resources */
  67. if (type == ALTERA_SPI_TYPE_SUBDEV) {
  68. struct resource *regoff;
  69. hw->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  70. if (!hw->regmap) {
  71. dev_err(&pdev->dev, "get regmap failed\n");
  72. goto exit;
  73. }
  74. regoff = platform_get_resource(pdev, IORESOURCE_REG, 0);
  75. if (regoff)
  76. hw->regoff = regoff->start;
  77. } else {
  78. void __iomem *res;
  79. res = devm_platform_ioremap_resource(pdev, 0);
  80. if (IS_ERR(res)) {
  81. err = PTR_ERR(res);
  82. goto exit;
  83. }
  84. hw->regmap = devm_regmap_init_mmio(&pdev->dev, res,
  85. &spi_altera_config);
  86. if (IS_ERR(hw->regmap)) {
  87. dev_err(&pdev->dev, "regmap mmio init failed\n");
  88. err = PTR_ERR(hw->regmap);
  89. goto exit;
  90. }
  91. }
  92. altera_spi_init_master(master);
  93. /* irq is optional */
  94. hw->irq = platform_get_irq(pdev, 0);
  95. if (hw->irq >= 0) {
  96. err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
  97. pdev->name, master);
  98. if (err)
  99. goto exit;
  100. }
  101. err = devm_spi_register_master(&pdev->dev, master);
  102. if (err)
  103. goto exit;
  104. if (pdata) {
  105. for (i = 0; i < pdata->num_devices; i++) {
  106. if (!spi_new_device(master, pdata->devices + i))
  107. dev_warn(&pdev->dev,
  108. "unable to create SPI device: %s\n",
  109. pdata->devices[i].modalias);
  110. }
  111. }
  112. dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq);
  113. return 0;
  114. exit:
  115. spi_master_put(master);
  116. return err;
  117. }
  118. #ifdef CONFIG_OF
  119. static const struct of_device_id altera_spi_match[] = {
  120. { .compatible = "ALTR,spi-1.0", },
  121. { .compatible = "altr,spi-1.0", },
  122. {},
  123. };
  124. MODULE_DEVICE_TABLE(of, altera_spi_match);
  125. #endif /* CONFIG_OF */
  126. static const struct platform_device_id altera_spi_ids[] = {
  127. { DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN },
  128. { "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV },
  129. { }
  130. };
  131. MODULE_DEVICE_TABLE(platform, altera_spi_ids);
  132. static struct platform_driver altera_spi_driver = {
  133. .probe = altera_spi_probe,
  134. .driver = {
  135. .name = DRV_NAME,
  136. .pm = NULL,
  137. .of_match_table = of_match_ptr(altera_spi_match),
  138. },
  139. .id_table = altera_spi_ids,
  140. };
  141. module_platform_driver(altera_spi_driver);
  142. MODULE_DESCRIPTION("Altera SPI driver");
  143. MODULE_AUTHOR("Thomas Chou <[email protected]>");
  144. MODULE_LICENSE("GPL");
  145. MODULE_ALIAS("platform:" DRV_NAME);