Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Altera SPI driver
0004  *
0005  * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
0006  *
0007  * Based on spi_s3c24xx.c, which is:
0008  * Copyright (c) 2006 Ben Dooks
0009  * Copyright (c) 2006 Simtec Electronics
0010  *  Ben Dooks <ben@simtec.co.uk>
0011  */
0012 
0013 #include <linux/interrupt.h>
0014 #include <linux/errno.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/spi/altera.h>
0018 #include <linux/spi/spi.h>
0019 #include <linux/io.h>
0020 #include <linux/of.h>
0021 
0022 #define DRV_NAME "spi_altera"
0023 
0024 enum altera_spi_type {
0025     ALTERA_SPI_TYPE_UNKNOWN,
0026     ALTERA_SPI_TYPE_SUBDEV,
0027 };
0028 
0029 static const struct regmap_config spi_altera_config = {
0030     .reg_bits = 32,
0031     .reg_stride = 4,
0032     .val_bits = 32,
0033     .fast_io = true,
0034 };
0035 
0036 static int altera_spi_probe(struct platform_device *pdev)
0037 {
0038     const struct platform_device_id *platid = platform_get_device_id(pdev);
0039     struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev);
0040     enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN;
0041     struct altera_spi *hw;
0042     struct spi_master *master;
0043     int err = -ENODEV;
0044     u16 i;
0045 
0046     master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
0047     if (!master)
0048         return err;
0049 
0050     /* setup the master state. */
0051     master->bus_num = -1;
0052 
0053     if (pdata) {
0054         if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) {
0055             dev_err(&pdev->dev,
0056                 "Invalid number of chipselect: %u\n",
0057                 pdata->num_chipselect);
0058             err = -EINVAL;
0059             goto exit;
0060         }
0061 
0062         master->num_chipselect = pdata->num_chipselect;
0063         master->mode_bits = pdata->mode_bits;
0064         master->bits_per_word_mask = pdata->bits_per_word_mask;
0065     } else {
0066         master->num_chipselect = 16;
0067         master->mode_bits = SPI_CS_HIGH;
0068         master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
0069     }
0070 
0071     master->dev.of_node = pdev->dev.of_node;
0072 
0073     hw = spi_master_get_devdata(master);
0074     hw->dev = &pdev->dev;
0075 
0076     if (platid)
0077         type = platid->driver_data;
0078 
0079     /* find and map our resources */
0080     if (type == ALTERA_SPI_TYPE_SUBDEV) {
0081         struct resource *regoff;
0082 
0083         hw->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0084         if (!hw->regmap) {
0085             dev_err(&pdev->dev, "get regmap failed\n");
0086             goto exit;
0087         }
0088 
0089         regoff = platform_get_resource(pdev, IORESOURCE_REG, 0);
0090         if (regoff)
0091             hw->regoff = regoff->start;
0092     } else {
0093         void __iomem *res;
0094 
0095         res = devm_platform_ioremap_resource(pdev, 0);
0096         if (IS_ERR(res)) {
0097             err = PTR_ERR(res);
0098             goto exit;
0099         }
0100 
0101         hw->regmap = devm_regmap_init_mmio(&pdev->dev, res,
0102                            &spi_altera_config);
0103         if (IS_ERR(hw->regmap)) {
0104             dev_err(&pdev->dev, "regmap mmio init failed\n");
0105             err = PTR_ERR(hw->regmap);
0106             goto exit;
0107         }
0108     }
0109 
0110     altera_spi_init_master(master);
0111 
0112     /* irq is optional */
0113     hw->irq = platform_get_irq(pdev, 0);
0114     if (hw->irq >= 0) {
0115         err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
0116                        pdev->name, master);
0117         if (err)
0118             goto exit;
0119     }
0120 
0121     err = devm_spi_register_master(&pdev->dev, master);
0122     if (err)
0123         goto exit;
0124 
0125     if (pdata) {
0126         for (i = 0; i < pdata->num_devices; i++) {
0127             if (!spi_new_device(master, pdata->devices + i))
0128                 dev_warn(&pdev->dev,
0129                      "unable to create SPI device: %s\n",
0130                      pdata->devices[i].modalias);
0131         }
0132     }
0133 
0134     dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq);
0135 
0136     return 0;
0137 exit:
0138     spi_master_put(master);
0139     return err;
0140 }
0141 
0142 #ifdef CONFIG_OF
0143 static const struct of_device_id altera_spi_match[] = {
0144     { .compatible = "ALTR,spi-1.0", },
0145     { .compatible = "altr,spi-1.0", },
0146     {},
0147 };
0148 MODULE_DEVICE_TABLE(of, altera_spi_match);
0149 #endif /* CONFIG_OF */
0150 
0151 static const struct platform_device_id altera_spi_ids[] = {
0152     { DRV_NAME,     ALTERA_SPI_TYPE_UNKNOWN },
0153     { "subdev_spi_altera",  ALTERA_SPI_TYPE_SUBDEV },
0154     { }
0155 };
0156 MODULE_DEVICE_TABLE(platform, altera_spi_ids);
0157 
0158 static struct platform_driver altera_spi_driver = {
0159     .probe = altera_spi_probe,
0160     .driver = {
0161         .name = DRV_NAME,
0162         .pm = NULL,
0163         .of_match_table = of_match_ptr(altera_spi_match),
0164     },
0165     .id_table   = altera_spi_ids,
0166 };
0167 module_platform_driver(altera_spi_driver);
0168 
0169 MODULE_DESCRIPTION("Altera SPI driver");
0170 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
0171 MODULE_LICENSE("GPL");
0172 MODULE_ALIAS("platform:" DRV_NAME);