Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // DFL bus driver for Altera SPI Master
0004 //
0005 // Copyright (C) 2020 Intel Corporation, Inc.
0006 //
0007 // Authors:
0008 //   Matthew Gerlach <matthew.gerlach@linux.intel.com>
0009 //
0010 
0011 #include <linux/types.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/stddef.h>
0015 #include <linux/errno.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/io.h>
0018 #include <linux/bitfield.h>
0019 #include <linux/io-64-nonatomic-lo-hi.h>
0020 #include <linux/regmap.h>
0021 #include <linux/spi/spi.h>
0022 #include <linux/spi/altera.h>
0023 #include <linux/dfl.h>
0024 
0025 #define FME_FEATURE_ID_MAX10_SPI    0xe
0026 #define FME_FEATURE_REV_MAX10_SPI_N5010 0x1
0027 
0028 #define SPI_CORE_PARAMETER      0x8
0029 #define SHIFT_MODE              BIT_ULL(1)
0030 #define SHIFT_MODE_MSB          0
0031 #define SHIFT_MODE_LSB          1
0032 #define DATA_WIDTH              GENMASK_ULL(7, 2)
0033 #define NUM_CHIPSELECT          GENMASK_ULL(13, 8)
0034 #define CLK_POLARITY            BIT_ULL(14)
0035 #define CLK_PHASE               BIT_ULL(15)
0036 #define PERIPHERAL_ID           GENMASK_ULL(47, 32)
0037 #define SPI_CLK                 GENMASK_ULL(31, 22)
0038 #define SPI_INDIRECT_ACC_OFST   0x10
0039 
0040 #define INDIRECT_ADDR           (SPI_INDIRECT_ACC_OFST+0x0)
0041 #define INDIRECT_WR             BIT_ULL(8)
0042 #define INDIRECT_RD             BIT_ULL(9)
0043 #define INDIRECT_RD_DATA        (SPI_INDIRECT_ACC_OFST+0x8)
0044 #define INDIRECT_DATA_MASK      GENMASK_ULL(31, 0)
0045 #define INDIRECT_DEBUG          BIT_ULL(32)
0046 #define INDIRECT_WR_DATA        (SPI_INDIRECT_ACC_OFST+0x10)
0047 #define INDIRECT_TIMEOUT        10000
0048 
0049 static int indirect_bus_reg_read(void *context, unsigned int reg,
0050                  unsigned int *val)
0051 {
0052     void __iomem *base = context;
0053     int loops;
0054     u64 v;
0055 
0056     writeq((reg >> 2) | INDIRECT_RD, base + INDIRECT_ADDR);
0057 
0058     loops = 0;
0059     while ((readq(base + INDIRECT_ADDR) & INDIRECT_RD) &&
0060            (loops++ < INDIRECT_TIMEOUT))
0061         cpu_relax();
0062 
0063     if (loops >= INDIRECT_TIMEOUT) {
0064         pr_err("%s timed out %d\n", __func__, loops);
0065         return -ETIME;
0066     }
0067 
0068     v = readq(base + INDIRECT_RD_DATA);
0069 
0070     *val = v & INDIRECT_DATA_MASK;
0071 
0072     return 0;
0073 }
0074 
0075 static int indirect_bus_reg_write(void *context, unsigned int reg,
0076                   unsigned int val)
0077 {
0078     void __iomem *base = context;
0079     int loops;
0080 
0081     writeq(val, base + INDIRECT_WR_DATA);
0082     writeq((reg >> 2) | INDIRECT_WR, base + INDIRECT_ADDR);
0083 
0084     loops = 0;
0085     while ((readq(base + INDIRECT_ADDR) & INDIRECT_WR) &&
0086            (loops++ < INDIRECT_TIMEOUT))
0087         cpu_relax();
0088 
0089     if (loops >= INDIRECT_TIMEOUT) {
0090         pr_err("%s timed out %d\n", __func__, loops);
0091         return -ETIME;
0092     }
0093     return 0;
0094 }
0095 
0096 static const struct regmap_config indirect_regbus_cfg = {
0097     .reg_bits = 32,
0098     .reg_stride = 4,
0099     .val_bits = 32,
0100     .fast_io = true,
0101     .max_register = 24,
0102 
0103     .reg_write = indirect_bus_reg_write,
0104     .reg_read = indirect_bus_reg_read,
0105 };
0106 
0107 static void config_spi_master(void __iomem *base, struct spi_master *master)
0108 {
0109     u64 v;
0110 
0111     v = readq(base + SPI_CORE_PARAMETER);
0112 
0113     master->mode_bits = SPI_CS_HIGH;
0114     if (FIELD_GET(CLK_POLARITY, v))
0115         master->mode_bits |= SPI_CPOL;
0116     if (FIELD_GET(CLK_PHASE, v))
0117         master->mode_bits |= SPI_CPHA;
0118 
0119     master->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v);
0120     master->bits_per_word_mask =
0121         SPI_BPW_RANGE_MASK(1, FIELD_GET(DATA_WIDTH, v));
0122 }
0123 
0124 static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
0125 {
0126     struct spi_board_info board_info = { 0 };
0127     struct device *dev = &dfl_dev->dev;
0128     struct spi_master *master;
0129     struct altera_spi *hw;
0130     void __iomem *base;
0131     int err;
0132 
0133     master = devm_spi_alloc_master(dev, sizeof(struct altera_spi));
0134     if (!master)
0135         return -ENOMEM;
0136 
0137     master->bus_num = -1;
0138 
0139     hw = spi_master_get_devdata(master);
0140 
0141     hw->dev = dev;
0142 
0143     base = devm_ioremap_resource(dev, &dfl_dev->mmio_res);
0144 
0145     if (IS_ERR(base))
0146         return PTR_ERR(base);
0147 
0148     config_spi_master(base, master);
0149     dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
0150         master->num_chipselect, master->bits_per_word_mask,
0151         master->mode_bits);
0152 
0153     hw->regmap = devm_regmap_init(dev, NULL, base, &indirect_regbus_cfg);
0154     if (IS_ERR(hw->regmap))
0155         return PTR_ERR(hw->regmap);
0156 
0157     hw->irq = -EINVAL;
0158 
0159     altera_spi_init_master(master);
0160 
0161     err = devm_spi_register_master(dev, master);
0162     if (err)
0163         return dev_err_probe(dev, err, "%s failed to register spi master\n",
0164                      __func__);
0165 
0166     if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010)
0167         strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE);
0168     else
0169         strscpy(board_info.modalias, "m10-d5005", SPI_NAME_SIZE);
0170 
0171     board_info.max_speed_hz = 12500000;
0172     board_info.bus_num = 0;
0173     board_info.chip_select = 0;
0174 
0175     if (!spi_new_device(master, &board_info)) {
0176         dev_err(dev, "%s failed to create SPI device: %s\n",
0177             __func__, board_info.modalias);
0178     }
0179 
0180     return 0;
0181 }
0182 
0183 static const struct dfl_device_id dfl_spi_altera_ids[] = {
0184     { FME_ID, FME_FEATURE_ID_MAX10_SPI },
0185     { }
0186 };
0187 
0188 static struct dfl_driver dfl_spi_altera_driver = {
0189     .drv    = {
0190         .name       = "dfl-spi-altera",
0191     },
0192     .id_table = dfl_spi_altera_ids,
0193     .probe   = dfl_spi_altera_probe,
0194 };
0195 
0196 module_dfl_driver(dfl_spi_altera_driver);
0197 
0198 MODULE_DEVICE_TABLE(dfl, dfl_spi_altera_ids);
0199 MODULE_DESCRIPTION("DFL spi altera driver");
0200 MODULE_AUTHOR("Intel Corporation");
0201 MODULE_LICENSE("GPL v2");