1 // SPDX-License-Identifier: GPL-2.0
3 // DFL bus driver for Altera SPI Master
5 // Copyright (C) 2020 Intel Corporation, Inc.
8 // Matthew Gerlach <matthew.gerlach@linux.intel.com>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/stddef.h>
15 #include <linux/errno.h>
16 #include <linux/platform_device.h>
18 #include <linux/bitfield.h>
19 #include <linux/io-64-nonatomic-lo-hi.h>
20 #include <linux/regmap.h>
21 #include <linux/spi/spi.h>
22 #include <linux/spi/altera.h>
23 #include <linux/dfl.h>
25 #define FME_FEATURE_ID_MAX10_SPI 0xe
26 #define FME_FEATURE_REV_MAX10_SPI_N5010 0x1
28 #define SPI_CORE_PARAMETER 0x8
29 #define SHIFT_MODE BIT_ULL(1)
30 #define SHIFT_MODE_MSB 0
31 #define SHIFT_MODE_LSB 1
32 #define DATA_WIDTH GENMASK_ULL(7, 2)
33 #define NUM_CHIPSELECT GENMASK_ULL(13, 8)
34 #define CLK_POLARITY BIT_ULL(14)
35 #define CLK_PHASE BIT_ULL(15)
36 #define PERIPHERAL_ID GENMASK_ULL(47, 32)
37 #define SPI_CLK GENMASK_ULL(31, 22)
38 #define SPI_INDIRECT_ACC_OFST 0x10
40 #define INDIRECT_ADDR (SPI_INDIRECT_ACC_OFST+0x0)
41 #define INDIRECT_WR BIT_ULL(8)
42 #define INDIRECT_RD BIT_ULL(9)
43 #define INDIRECT_RD_DATA (SPI_INDIRECT_ACC_OFST+0x8)
44 #define INDIRECT_DATA_MASK GENMASK_ULL(31, 0)
45 #define INDIRECT_DEBUG BIT_ULL(32)
46 #define INDIRECT_WR_DATA (SPI_INDIRECT_ACC_OFST+0x10)
47 #define INDIRECT_TIMEOUT 10000
49 static int indirect_bus_reg_read(void *context
, unsigned int reg
,
52 void __iomem
*base
= context
;
56 writeq((reg
>> 2) | INDIRECT_RD
, base
+ INDIRECT_ADDR
);
59 while ((readq(base
+ INDIRECT_ADDR
) & INDIRECT_RD
) &&
60 (loops
++ < INDIRECT_TIMEOUT
))
63 if (loops
>= INDIRECT_TIMEOUT
) {
64 pr_err("%s timed out %d\n", __func__
, loops
);
68 v
= readq(base
+ INDIRECT_RD_DATA
);
70 *val
= v
& INDIRECT_DATA_MASK
;
75 static int indirect_bus_reg_write(void *context
, unsigned int reg
,
78 void __iomem
*base
= context
;
81 writeq(val
, base
+ INDIRECT_WR_DATA
);
82 writeq((reg
>> 2) | INDIRECT_WR
, base
+ INDIRECT_ADDR
);
85 while ((readq(base
+ INDIRECT_ADDR
) & INDIRECT_WR
) &&
86 (loops
++ < INDIRECT_TIMEOUT
))
89 if (loops
>= INDIRECT_TIMEOUT
) {
90 pr_err("%s timed out %d\n", __func__
, loops
);
96 static const struct regmap_config indirect_regbus_cfg
= {
103 .reg_write
= indirect_bus_reg_write
,
104 .reg_read
= indirect_bus_reg_read
,
107 static void config_spi_host(void __iomem
*base
, struct spi_controller
*host
)
111 v
= readq(base
+ SPI_CORE_PARAMETER
);
113 host
->mode_bits
= SPI_CS_HIGH
;
114 if (FIELD_GET(CLK_POLARITY
, v
))
115 host
->mode_bits
|= SPI_CPOL
;
116 if (FIELD_GET(CLK_PHASE
, v
))
117 host
->mode_bits
|= SPI_CPHA
;
119 host
->num_chipselect
= FIELD_GET(NUM_CHIPSELECT
, v
);
120 host
->bits_per_word_mask
=
121 SPI_BPW_RANGE_MASK(1, FIELD_GET(DATA_WIDTH
, v
));
124 static int dfl_spi_altera_probe(struct dfl_device
*dfl_dev
)
126 struct spi_board_info board_info
= { 0 };
127 struct device
*dev
= &dfl_dev
->dev
;
128 struct spi_controller
*host
;
129 struct altera_spi
*hw
;
133 host
= devm_spi_alloc_host(dev
, sizeof(struct altera_spi
));
139 hw
= spi_controller_get_devdata(host
);
143 base
= devm_ioremap_resource(dev
, &dfl_dev
->mmio_res
);
146 return PTR_ERR(base
);
148 config_spi_host(base
, host
);
149 dev_dbg(dev
, "%s cs %u bpm 0x%x mode 0x%x\n", __func__
,
150 host
->num_chipselect
, host
->bits_per_word_mask
,
153 hw
->regmap
= devm_regmap_init(dev
, NULL
, base
, &indirect_regbus_cfg
);
154 if (IS_ERR(hw
->regmap
))
155 return PTR_ERR(hw
->regmap
);
159 altera_spi_init_host(host
);
161 err
= devm_spi_register_controller(dev
, host
);
163 return dev_err_probe(dev
, err
, "%s failed to register spi host\n",
166 if (dfl_dev
->revision
== FME_FEATURE_REV_MAX10_SPI_N5010
)
167 strscpy(board_info
.modalias
, "m10-n5010", SPI_NAME_SIZE
);
169 strscpy(board_info
.modalias
, "m10-d5005", SPI_NAME_SIZE
);
171 board_info
.max_speed_hz
= 12500000;
172 board_info
.bus_num
= 0;
173 board_info
.chip_select
= 0;
175 if (!spi_new_device(host
, &board_info
)) {
176 dev_err(dev
, "%s failed to create SPI device: %s\n",
177 __func__
, board_info
.modalias
);
183 static const struct dfl_device_id dfl_spi_altera_ids
[] = {
184 { FME_ID
, FME_FEATURE_ID_MAX10_SPI
},
188 static struct dfl_driver dfl_spi_altera_driver
= {
190 .name
= "dfl-spi-altera",
192 .id_table
= dfl_spi_altera_ids
,
193 .probe
= dfl_spi_altera_probe
,
196 module_dfl_driver(dfl_spi_altera_driver
);
198 MODULE_DEVICE_TABLE(dfl
, dfl_spi_altera_ids
);
199 MODULE_DESCRIPTION("DFL spi altera driver");
200 MODULE_AUTHOR("Intel Corporation");
201 MODULE_LICENSE("GPL v2");