1ace55c41STomer Maimon // SPDX-License-Identifier: GPL-2.0
2ace55c41STomer Maimon // Copyright (c) 2019 Nuvoton Technology corporation.
3ace55c41STomer Maimon
40ec544ceSAndy Shevchenko #include <linux/bits.h>
5ace55c41STomer Maimon #include <linux/init.h>
6ace55c41STomer Maimon #include <linux/kernel.h>
7ace55c41STomer Maimon #include <linux/device.h>
8ace55c41STomer Maimon #include <linux/module.h>
9ace55c41STomer Maimon #include <linux/ioport.h>
10ace55c41STomer Maimon #include <linux/clk.h>
11ace55c41STomer Maimon #include <linux/platform_device.h>
12ace55c41STomer Maimon #include <linux/io.h>
13ace55c41STomer Maimon #include <linux/vmalloc.h>
14ace55c41STomer Maimon #include <linux/regmap.h>
15749396cbSRob Herring #include <linux/of.h>
16ace55c41STomer Maimon #include <linux/spi/spi-mem.h>
17ace55c41STomer Maimon #include <linux/mfd/syscon.h>
18ace55c41STomer Maimon
19ace55c41STomer Maimon /* NPCM7xx GCR module */
20ace55c41STomer Maimon #define NPCM7XX_INTCR3_OFFSET 0x9C
21ace55c41STomer Maimon #define NPCM7XX_INTCR3_FIU_FIX BIT(6)
22ace55c41STomer Maimon
23ace55c41STomer Maimon /* Flash Interface Unit (FIU) Registers */
24ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG 0x00
25ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG 0x04
26ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG 0x08
27ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS 0x0C
28ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD 0x10
29ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR 0x14
30ace55c41STomer Maimon #define NPCM_FIU_PRT_CFG 0x18
31ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0 0x20
32ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1 0x24
33ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2 0x28
34ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3 0x2C
35ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0 0x30
36ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1 0x34
37ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2 0x38
38ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3 0x3C
39650b014fSTomer Maimon #define NPCM_FIU_CFG 0x78
40ace55c41STomer Maimon #define NPCM_FIU_MAX_REG_LIMIT 0x80
41ace55c41STomer Maimon
42ace55c41STomer Maimon /* FIU Direct Read Configuration Register */
43ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_LCK BIT(31)
44ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_R_BURST GENMASK(25, 24)
45ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_ADDSIZ GENMASK(17, 16)
46ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_DBW GENMASK(13, 12)
47ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_ACCTYPE GENMASK(9, 8)
48ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_RDCMD GENMASK(7, 0)
49ace55c41STomer Maimon #define NPCM_FIU_DRD_ADDSIZ_SHIFT 16
50ace55c41STomer Maimon #define NPCM_FIU_DRD_DBW_SHIFT 12
51ace55c41STomer Maimon #define NPCM_FIU_DRD_ACCTYPE_SHIFT 8
52ace55c41STomer Maimon
53ace55c41STomer Maimon /* FIU Direct Write Configuration Register */
54ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_LCK BIT(31)
55ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_W_BURST GENMASK(25, 24)
56ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_ADDSIZ GENMASK(17, 16)
57ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_ABPCK GENMASK(11, 10)
58ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_DBPCK GENMASK(9, 8)
59ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_WRCMD GENMASK(7, 0)
60ace55c41STomer Maimon #define NPCM_FIU_DWR_ADDSIZ_SHIFT 16
61ace55c41STomer Maimon #define NPCM_FIU_DWR_ABPCK_SHIFT 10
62ace55c41STomer Maimon #define NPCM_FIU_DWR_DBPCK_SHIFT 8
63ace55c41STomer Maimon
64ace55c41STomer Maimon /* FIU UMA Configuration Register */
65ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_LCK BIT(31)
66ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMMLCK BIT(30)
67ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDATSIZ GENMASK(28, 24)
68ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBSIZ GENMASK(23, 21)
69ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDATSIZ GENMASK(20, 16)
70ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADDSIZ GENMASK(13, 11)
71ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMDSIZ BIT(10)
72ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDBPCK GENMASK(9, 8)
73ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBPCK GENMASK(7, 6)
74ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDBPCK GENMASK(5, 4)
75ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADBPCK GENMASK(3, 2)
76ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMBPCK GENMASK(1, 0)
77ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADBPCK_SHIFT 2
78ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDBPCK_SHIFT 4
79ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBPCK_SHIFT 6
80ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDBPCK_SHIFT 8
81ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT 11
82ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT 16
83ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBSIZ_SHIFT 21
84ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT 24
85ace55c41STomer Maimon
86ace55c41STomer Maimon /* FIU UMA Control and Status Register */
87ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_RDYIE BIT(25)
88ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_RDYST BIT(24)
89ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_SW_CS BIT(16)
90ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_DEV_NUM GENMASK(9, 8)
91ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_EXEC_DONE BIT(0)
92ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT 8
93ace55c41STomer Maimon
94ace55c41STomer Maimon /* FIU UMA Command Register */
95ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM3 GENMASK(31, 24)
96ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM2 GENMASK(23, 16)
97ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM1 GENMASK(15, 8)
98ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_CMD GENMASK(7, 0)
99ace55c41STomer Maimon
100ace55c41STomer Maimon /* FIU UMA Address Register */
101ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_UMA_ADDR GENMASK(31, 0)
102ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB3 GENMASK(31, 24)
103ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB2 GENMASK(23, 16)
104ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB1 GENMASK(15, 8)
105ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB0 GENMASK(7, 0)
106ace55c41STomer Maimon
107ace55c41STomer Maimon /* FIU UMA Write Data Bytes 0-3 Register */
108ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB3 GENMASK(31, 24)
109ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB2 GENMASK(23, 16)
110ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB1 GENMASK(15, 8)
111ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB0 GENMASK(7, 0)
112ace55c41STomer Maimon
113ace55c41STomer Maimon /* FIU UMA Write Data Bytes 4-7 Register */
114ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB7 GENMASK(31, 24)
115ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB6 GENMASK(23, 16)
116ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB5 GENMASK(15, 8)
117ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB4 GENMASK(7, 0)
118ace55c41STomer Maimon
119ace55c41STomer Maimon /* FIU UMA Write Data Bytes 8-11 Register */
120ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB11 GENMASK(31, 24)
121ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB10 GENMASK(23, 16)
122ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB9 GENMASK(15, 8)
123ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB8 GENMASK(7, 0)
124ace55c41STomer Maimon
125ace55c41STomer Maimon /* FIU UMA Write Data Bytes 12-15 Register */
126ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB15 GENMASK(31, 24)
127ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB14 GENMASK(23, 16)
128ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB13 GENMASK(15, 8)
129ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB12 GENMASK(7, 0)
130ace55c41STomer Maimon
131ace55c41STomer Maimon /* FIU UMA Read Data Bytes 0-3 Register */
132ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB3 GENMASK(31, 24)
133ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB2 GENMASK(23, 16)
134ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB1 GENMASK(15, 8)
135ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB0 GENMASK(7, 0)
136ace55c41STomer Maimon
137ace55c41STomer Maimon /* FIU UMA Read Data Bytes 4-7 Register */
138ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB15 GENMASK(31, 24)
139ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB14 GENMASK(23, 16)
140ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB13 GENMASK(15, 8)
141ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB12 GENMASK(7, 0)
142ace55c41STomer Maimon
143ace55c41STomer Maimon /* FIU UMA Read Data Bytes 8-11 Register */
144ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB15 GENMASK(31, 24)
145ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB14 GENMASK(23, 16)
146ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB13 GENMASK(15, 8)
147ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB12 GENMASK(7, 0)
148ace55c41STomer Maimon
149ace55c41STomer Maimon /* FIU UMA Read Data Bytes 12-15 Register */
150ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB15 GENMASK(31, 24)
151ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB14 GENMASK(23, 16)
152ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB13 GENMASK(15, 8)
153ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB12 GENMASK(7, 0)
154ace55c41STomer Maimon
155650b014fSTomer Maimon /* FIU Configuration Register */
156650b014fSTomer Maimon #define NPCM_FIU_CFG_FIU_FIX BIT(31)
157650b014fSTomer Maimon
158ace55c41STomer Maimon /* FIU Read Mode */
159ace55c41STomer Maimon enum {
160ace55c41STomer Maimon DRD_SINGLE_WIRE_MODE = 0,
161ace55c41STomer Maimon DRD_DUAL_IO_MODE = 1,
162ace55c41STomer Maimon DRD_QUAD_IO_MODE = 2,
163ace55c41STomer Maimon DRD_SPI_X_MODE = 3,
164ace55c41STomer Maimon };
165ace55c41STomer Maimon
166ace55c41STomer Maimon enum {
167ace55c41STomer Maimon DWR_ABPCK_BIT_PER_CLK = 0,
168ace55c41STomer Maimon DWR_ABPCK_2_BIT_PER_CLK = 1,
169ace55c41STomer Maimon DWR_ABPCK_4_BIT_PER_CLK = 2,
170ace55c41STomer Maimon };
171ace55c41STomer Maimon
172ace55c41STomer Maimon enum {
173ace55c41STomer Maimon DWR_DBPCK_BIT_PER_CLK = 0,
174ace55c41STomer Maimon DWR_DBPCK_2_BIT_PER_CLK = 1,
175ace55c41STomer Maimon DWR_DBPCK_4_BIT_PER_CLK = 2,
176ace55c41STomer Maimon };
177ace55c41STomer Maimon
178ace55c41STomer Maimon #define NPCM_FIU_DRD_16_BYTE_BURST 0x3000000
179ace55c41STomer Maimon #define NPCM_FIU_DWR_16_BYTE_BURST 0x3000000
180ace55c41STomer Maimon
181ace55c41STomer Maimon #define MAP_SIZE_128MB 0x8000000
182ace55c41STomer Maimon #define MAP_SIZE_16MB 0x1000000
183ace55c41STomer Maimon #define MAP_SIZE_8MB 0x800000
184ace55c41STomer Maimon
185ace55c41STomer Maimon #define FIU_DRD_MAX_DUMMY_NUMBER 3
186ace55c41STomer Maimon #define NPCM_MAX_CHIP_NUM 4
187ace55c41STomer Maimon #define CHUNK_SIZE 16
188ace55c41STomer Maimon #define UMA_MICRO_SEC_TIMEOUT 150
189ace55c41STomer Maimon
190ace55c41STomer Maimon enum {
191ace55c41STomer Maimon FIU0 = 0,
192ace55c41STomer Maimon FIU3,
193ace55c41STomer Maimon FIUX,
194650b014fSTomer Maimon FIU1,
195ace55c41STomer Maimon };
196ace55c41STomer Maimon
197ace55c41STomer Maimon struct npcm_fiu_info {
198ace55c41STomer Maimon char *name;
199ace55c41STomer Maimon u32 fiu_id;
200ace55c41STomer Maimon u32 max_map_size;
201ace55c41STomer Maimon u32 max_cs;
202ace55c41STomer Maimon };
203ace55c41STomer Maimon
204ace55c41STomer Maimon struct fiu_data {
205ace55c41STomer Maimon const struct npcm_fiu_info *npcm_fiu_data_info;
206ace55c41STomer Maimon int fiu_max;
207ace55c41STomer Maimon };
208ace55c41STomer Maimon
209b15e3bc7SJonathan Neuschäfer static const struct npcm_fiu_info npcm7xx_fiu_info[] = {
210ace55c41STomer Maimon {.name = "FIU0", .fiu_id = FIU0,
211ace55c41STomer Maimon .max_map_size = MAP_SIZE_128MB, .max_cs = 2},
212ace55c41STomer Maimon {.name = "FIU3", .fiu_id = FIU3,
213ace55c41STomer Maimon .max_map_size = MAP_SIZE_128MB, .max_cs = 4},
214ace55c41STomer Maimon {.name = "FIUX", .fiu_id = FIUX,
215ace55c41STomer Maimon .max_map_size = MAP_SIZE_16MB, .max_cs = 2} };
216ace55c41STomer Maimon
217b15e3bc7SJonathan Neuschäfer static const struct fiu_data npcm7xx_fiu_data = {
218b15e3bc7SJonathan Neuschäfer .npcm_fiu_data_info = npcm7xx_fiu_info,
219ace55c41STomer Maimon .fiu_max = 3,
220ace55c41STomer Maimon };
221ace55c41STomer Maimon
222650b014fSTomer Maimon static const struct npcm_fiu_info npxm8xx_fiu_info[] = {
223650b014fSTomer Maimon {.name = "FIU0", .fiu_id = FIU0,
224650b014fSTomer Maimon .max_map_size = MAP_SIZE_128MB, .max_cs = 2},
225650b014fSTomer Maimon {.name = "FIU3", .fiu_id = FIU3,
226650b014fSTomer Maimon .max_map_size = MAP_SIZE_128MB, .max_cs = 4},
227650b014fSTomer Maimon {.name = "FIUX", .fiu_id = FIUX,
228650b014fSTomer Maimon .max_map_size = MAP_SIZE_16MB, .max_cs = 2},
229650b014fSTomer Maimon {.name = "FIU1", .fiu_id = FIU1,
230650b014fSTomer Maimon .max_map_size = MAP_SIZE_16MB, .max_cs = 4} };
231650b014fSTomer Maimon
232650b014fSTomer Maimon static const struct fiu_data npxm8xx_fiu_data = {
233650b014fSTomer Maimon .npcm_fiu_data_info = npxm8xx_fiu_info,
234650b014fSTomer Maimon .fiu_max = 4,
235650b014fSTomer Maimon };
236650b014fSTomer Maimon
237ace55c41STomer Maimon struct npcm_fiu_spi;
238ace55c41STomer Maimon
239ace55c41STomer Maimon struct npcm_fiu_chip {
240ace55c41STomer Maimon void __iomem *flash_region_mapped_ptr;
241ace55c41STomer Maimon struct npcm_fiu_spi *fiu;
242ace55c41STomer Maimon unsigned long clkrate;
243ace55c41STomer Maimon u32 chipselect;
244ace55c41STomer Maimon };
245ace55c41STomer Maimon
246ace55c41STomer Maimon struct npcm_fiu_spi {
247ace55c41STomer Maimon struct npcm_fiu_chip chip[NPCM_MAX_CHIP_NUM];
248ace55c41STomer Maimon const struct npcm_fiu_info *info;
249ace55c41STomer Maimon struct spi_mem_op drd_op;
250ace55c41STomer Maimon struct resource *res_mem;
251ace55c41STomer Maimon struct regmap *regmap;
252ace55c41STomer Maimon unsigned long clkrate;
253ace55c41STomer Maimon struct device *dev;
254ace55c41STomer Maimon struct clk *clk;
255ace55c41STomer Maimon bool spix_mode;
256ace55c41STomer Maimon };
257ace55c41STomer Maimon
258ace55c41STomer Maimon static const struct regmap_config npcm_mtd_regmap_config = {
259ace55c41STomer Maimon .reg_bits = 32,
260ace55c41STomer Maimon .val_bits = 32,
261ace55c41STomer Maimon .reg_stride = 4,
262ace55c41STomer Maimon .max_register = NPCM_FIU_MAX_REG_LIMIT,
263ace55c41STomer Maimon };
264ace55c41STomer Maimon
npcm_fiu_set_drd(struct npcm_fiu_spi * fiu,const struct spi_mem_op * op)265ace55c41STomer Maimon static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
266ace55c41STomer Maimon const struct spi_mem_op *op)
267ace55c41STomer Maimon {
268ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
269ace55c41STomer Maimon NPCM_FIU_DRD_CFG_ACCTYPE,
270ace55c41STomer Maimon ilog2(op->addr.buswidth) <<
271ace55c41STomer Maimon NPCM_FIU_DRD_ACCTYPE_SHIFT);
272ace55c41STomer Maimon fiu->drd_op.addr.buswidth = op->addr.buswidth;
273ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
274ace55c41STomer Maimon NPCM_FIU_DRD_CFG_DBW,
2757c3193f7STomer Maimon op->dummy.nbytes << NPCM_FIU_DRD_DBW_SHIFT);
276ace55c41STomer Maimon fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
277ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
278ace55c41STomer Maimon NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
279ace55c41STomer Maimon fiu->drd_op.cmd.opcode = op->cmd.opcode;
280ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
281ace55c41STomer Maimon NPCM_FIU_DRD_CFG_ADDSIZ,
282ace55c41STomer Maimon (op->addr.nbytes - 3) << NPCM_FIU_DRD_ADDSIZ_SHIFT);
283ace55c41STomer Maimon fiu->drd_op.addr.nbytes = op->addr.nbytes;
284ace55c41STomer Maimon }
285ace55c41STomer Maimon
npcm_fiu_direct_read(struct spi_mem_dirmap_desc * desc,u64 offs,size_t len,void * buf)286ace55c41STomer Maimon static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
287ace55c41STomer Maimon u64 offs, size_t len, void *buf)
288ace55c41STomer Maimon {
289ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
2901f6c80a7SYang Yingliang spi_controller_get_devdata(desc->mem->spi->controller);
2919e264f3fSAmit Kumar Mahapatra via Alsa-devel struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
292ace55c41STomer Maimon void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
293ace55c41STomer Maimon offs);
294ace55c41STomer Maimon u8 *buf_rx = buf;
295ace55c41STomer Maimon u32 i;
296ace55c41STomer Maimon
297ace55c41STomer Maimon if (fiu->spix_mode) {
298ace55c41STomer Maimon for (i = 0 ; i < len ; i++)
299ace55c41STomer Maimon *(buf_rx + i) = ioread8(src + i);
300ace55c41STomer Maimon } else {
301ace55c41STomer Maimon if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth ||
302ace55c41STomer Maimon desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes ||
303ace55c41STomer Maimon desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode ||
304ace55c41STomer Maimon desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes)
305ace55c41STomer Maimon npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
306ace55c41STomer Maimon
307ace55c41STomer Maimon memcpy_fromio(buf_rx, src, len);
308ace55c41STomer Maimon }
309ace55c41STomer Maimon
310ace55c41STomer Maimon return len;
311ace55c41STomer Maimon }
312ace55c41STomer Maimon
npcm_fiu_direct_write(struct spi_mem_dirmap_desc * desc,u64 offs,size_t len,const void * buf)313ace55c41STomer Maimon static ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
314ace55c41STomer Maimon u64 offs, size_t len, const void *buf)
315ace55c41STomer Maimon {
316ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
3171f6c80a7SYang Yingliang spi_controller_get_devdata(desc->mem->spi->controller);
3189e264f3fSAmit Kumar Mahapatra via Alsa-devel struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
319ace55c41STomer Maimon void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
320ace55c41STomer Maimon offs);
321ace55c41STomer Maimon const u8 *buf_tx = buf;
322ace55c41STomer Maimon u32 i;
323ace55c41STomer Maimon
324ace55c41STomer Maimon if (fiu->spix_mode)
325ace55c41STomer Maimon for (i = 0 ; i < len ; i++)
326ace55c41STomer Maimon iowrite8(*(buf_tx + i), dst + i);
327ace55c41STomer Maimon else
328ace55c41STomer Maimon memcpy_toio(dst, buf_tx, len);
329ace55c41STomer Maimon
330ace55c41STomer Maimon return len;
331ace55c41STomer Maimon }
332ace55c41STomer Maimon
npcm_fiu_uma_read(struct spi_mem * mem,const struct spi_mem_op * op,u32 addr,bool is_address_size,u8 * data,u32 data_size)333ace55c41STomer Maimon static int npcm_fiu_uma_read(struct spi_mem *mem,
334ace55c41STomer Maimon const struct spi_mem_op *op, u32 addr,
335ace55c41STomer Maimon bool is_address_size, u8 *data, u32 data_size)
336ace55c41STomer Maimon {
337ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
3381f6c80a7SYang Yingliang spi_controller_get_devdata(mem->spi->controller);
339ace55c41STomer Maimon u32 uma_cfg = BIT(10);
340ace55c41STomer Maimon u32 data_reg[4];
341ace55c41STomer Maimon int ret;
342ace55c41STomer Maimon u32 val;
343ace55c41STomer Maimon u32 i;
344ace55c41STomer Maimon
345ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
346ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM,
3479e264f3fSAmit Kumar Mahapatra via Alsa-devel (spi_get_chipselect(mem->spi, 0) <<
348ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
349ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
350ace55c41STomer Maimon NPCM_FIU_UMA_CMD_CMD, op->cmd.opcode);
351ace55c41STomer Maimon
352ace55c41STomer Maimon if (is_address_size) {
353ace55c41STomer Maimon uma_cfg |= ilog2(op->cmd.buswidth);
354ace55c41STomer Maimon uma_cfg |= ilog2(op->addr.buswidth)
355ace55c41STomer Maimon << NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
356*2ec8b010SWilliam A. Kennington III if (op->dummy.nbytes)
357ace55c41STomer Maimon uma_cfg |= ilog2(op->dummy.buswidth)
358ace55c41STomer Maimon << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
359ace55c41STomer Maimon uma_cfg |= ilog2(op->data.buswidth)
360ace55c41STomer Maimon << NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
361ace55c41STomer Maimon uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
362ace55c41STomer Maimon uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
363ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, addr);
364ace55c41STomer Maimon } else {
365ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
366ace55c41STomer Maimon }
367ace55c41STomer Maimon
368ace55c41STomer Maimon uma_cfg |= data_size << NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT;
369ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
370ace55c41STomer Maimon regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
371ace55c41STomer Maimon NPCM_FIU_UMA_CTS_EXEC_DONE,
372ace55c41STomer Maimon NPCM_FIU_UMA_CTS_EXEC_DONE);
373ace55c41STomer Maimon ret = regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
374ace55c41STomer Maimon (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
375ace55c41STomer Maimon UMA_MICRO_SEC_TIMEOUT);
376ace55c41STomer Maimon if (ret)
377ace55c41STomer Maimon return ret;
378ace55c41STomer Maimon
379ace55c41STomer Maimon if (data_size) {
380ace55c41STomer Maimon for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
381ace55c41STomer Maimon regmap_read(fiu->regmap, NPCM_FIU_UMA_DR0 + (i * 4),
382ace55c41STomer Maimon &data_reg[i]);
383ace55c41STomer Maimon memcpy(data, data_reg, data_size);
384ace55c41STomer Maimon }
385ace55c41STomer Maimon
386ace55c41STomer Maimon return 0;
387ace55c41STomer Maimon }
388ace55c41STomer Maimon
npcm_fiu_uma_write(struct spi_mem * mem,const struct spi_mem_op * op,u8 cmd,bool is_address_size,u8 * data,u32 data_size)389ace55c41STomer Maimon static int npcm_fiu_uma_write(struct spi_mem *mem,
390ace55c41STomer Maimon const struct spi_mem_op *op, u8 cmd,
391ace55c41STomer Maimon bool is_address_size, u8 *data, u32 data_size)
392ace55c41STomer Maimon {
393ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
3941f6c80a7SYang Yingliang spi_controller_get_devdata(mem->spi->controller);
395ace55c41STomer Maimon u32 uma_cfg = BIT(10);
396ace55c41STomer Maimon u32 data_reg[4] = {0};
397ace55c41STomer Maimon u32 val;
398ace55c41STomer Maimon u32 i;
399ace55c41STomer Maimon
400ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
401ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM,
4029e264f3fSAmit Kumar Mahapatra via Alsa-devel (spi_get_chipselect(mem->spi, 0) <<
403ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
404ace55c41STomer Maimon
405ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
406ace55c41STomer Maimon NPCM_FIU_UMA_CMD_CMD, cmd);
407ace55c41STomer Maimon
408ace55c41STomer Maimon if (data_size) {
409ace55c41STomer Maimon memcpy(data_reg, data, data_size);
410ace55c41STomer Maimon for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
411ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_DW0 + (i * 4),
412ace55c41STomer Maimon data_reg[i]);
413ace55c41STomer Maimon }
414ace55c41STomer Maimon
415ace55c41STomer Maimon if (is_address_size) {
416ace55c41STomer Maimon uma_cfg |= ilog2(op->cmd.buswidth);
417ace55c41STomer Maimon uma_cfg |= ilog2(op->addr.buswidth) <<
418ace55c41STomer Maimon NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
419ace55c41STomer Maimon uma_cfg |= ilog2(op->data.buswidth) <<
420ace55c41STomer Maimon NPCM_FIU_UMA_CFG_WDBPCK_SHIFT;
421ace55c41STomer Maimon uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
422ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, op->addr.val);
423ace55c41STomer Maimon } else {
424ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
425ace55c41STomer Maimon }
426ace55c41STomer Maimon
427ace55c41STomer Maimon uma_cfg |= (data_size << NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT);
428ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
429ace55c41STomer Maimon
430ace55c41STomer Maimon regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
431ace55c41STomer Maimon NPCM_FIU_UMA_CTS_EXEC_DONE,
432ace55c41STomer Maimon NPCM_FIU_UMA_CTS_EXEC_DONE);
433ace55c41STomer Maimon
434ace55c41STomer Maimon return regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
435ace55c41STomer Maimon (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
436ace55c41STomer Maimon UMA_MICRO_SEC_TIMEOUT);
437ace55c41STomer Maimon }
438ace55c41STomer Maimon
npcm_fiu_manualwrite(struct spi_mem * mem,const struct spi_mem_op * op)439ace55c41STomer Maimon static int npcm_fiu_manualwrite(struct spi_mem *mem,
440ace55c41STomer Maimon const struct spi_mem_op *op)
441ace55c41STomer Maimon {
442ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
4431f6c80a7SYang Yingliang spi_controller_get_devdata(mem->spi->controller);
444ace55c41STomer Maimon u8 *data = (u8 *)op->data.buf.out;
445ace55c41STomer Maimon u32 num_data_chunks;
446ace55c41STomer Maimon u32 remain_data;
447ace55c41STomer Maimon u32 idx = 0;
448ace55c41STomer Maimon int ret;
449ace55c41STomer Maimon
450ace55c41STomer Maimon num_data_chunks = op->data.nbytes / CHUNK_SIZE;
451ace55c41STomer Maimon remain_data = op->data.nbytes % CHUNK_SIZE;
452ace55c41STomer Maimon
453ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
454ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM,
4559e264f3fSAmit Kumar Mahapatra via Alsa-devel (spi_get_chipselect(mem->spi, 0) <<
456ace55c41STomer Maimon NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
457ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
458ace55c41STomer Maimon NPCM_FIU_UMA_CTS_SW_CS, 0);
459ace55c41STomer Maimon
460ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, true, NULL, 0);
461ace55c41STomer Maimon if (ret)
462ace55c41STomer Maimon return ret;
463ace55c41STomer Maimon
464ace55c41STomer Maimon /* Starting the data writing loop in multiples of 8 */
465ace55c41STomer Maimon for (idx = 0; idx < num_data_chunks; ++idx) {
466ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, data[0], false,
467ace55c41STomer Maimon &data[1], CHUNK_SIZE - 1);
468ace55c41STomer Maimon if (ret)
469ace55c41STomer Maimon return ret;
470ace55c41STomer Maimon
471ace55c41STomer Maimon data += CHUNK_SIZE;
472ace55c41STomer Maimon }
473ace55c41STomer Maimon
474ace55c41STomer Maimon /* Handling chunk remains */
475ace55c41STomer Maimon if (remain_data > 0) {
476ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, data[0], false,
477ace55c41STomer Maimon &data[1], remain_data - 1);
478ace55c41STomer Maimon if (ret)
479ace55c41STomer Maimon return ret;
480ace55c41STomer Maimon }
481ace55c41STomer Maimon
482ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
483ace55c41STomer Maimon NPCM_FIU_UMA_CTS_SW_CS, NPCM_FIU_UMA_CTS_SW_CS);
484ace55c41STomer Maimon
485ace55c41STomer Maimon return 0;
486ace55c41STomer Maimon }
487ace55c41STomer Maimon
npcm_fiu_read(struct spi_mem * mem,const struct spi_mem_op * op)488ace55c41STomer Maimon static int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op)
489ace55c41STomer Maimon {
490ace55c41STomer Maimon u8 *data = op->data.buf.in;
491ace55c41STomer Maimon int i, readlen, currlen;
492ace55c41STomer Maimon u8 *buf_ptr;
493ace55c41STomer Maimon u32 addr;
494ace55c41STomer Maimon int ret;
495ace55c41STomer Maimon
496ace55c41STomer Maimon i = 0;
497ace55c41STomer Maimon currlen = op->data.nbytes;
498ace55c41STomer Maimon
499ace55c41STomer Maimon do {
500ace55c41STomer Maimon addr = ((u32)op->addr.val + i);
501ace55c41STomer Maimon if (currlen < 16)
502ace55c41STomer Maimon readlen = currlen;
503ace55c41STomer Maimon else
504ace55c41STomer Maimon readlen = 16;
505ace55c41STomer Maimon
506ace55c41STomer Maimon buf_ptr = data + i;
507ace55c41STomer Maimon ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr,
508ace55c41STomer Maimon readlen);
509ace55c41STomer Maimon if (ret)
510ace55c41STomer Maimon return ret;
511ace55c41STomer Maimon
512ace55c41STomer Maimon i += readlen;
513ace55c41STomer Maimon currlen -= 16;
514ace55c41STomer Maimon } while (currlen > 0);
515ace55c41STomer Maimon
516ace55c41STomer Maimon return 0;
517ace55c41STomer Maimon }
518ace55c41STomer Maimon
npcm_fiux_set_direct_wr(struct npcm_fiu_spi * fiu)519ace55c41STomer Maimon static void npcm_fiux_set_direct_wr(struct npcm_fiu_spi *fiu)
520ace55c41STomer Maimon {
521ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_DWR_CFG,
522ace55c41STomer Maimon NPCM_FIU_DWR_16_BYTE_BURST);
523ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
524ace55c41STomer Maimon NPCM_FIU_DWR_CFG_ABPCK,
525ace55c41STomer Maimon DWR_ABPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_ABPCK_SHIFT);
526ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
527ace55c41STomer Maimon NPCM_FIU_DWR_CFG_DBPCK,
528ace55c41STomer Maimon DWR_DBPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_DBPCK_SHIFT);
529ace55c41STomer Maimon }
530ace55c41STomer Maimon
npcm_fiux_set_direct_rd(struct npcm_fiu_spi * fiu)531ace55c41STomer Maimon static void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
532ace55c41STomer Maimon {
533ace55c41STomer Maimon u32 rx_dummy = 0;
534ace55c41STomer Maimon
535ace55c41STomer Maimon regmap_write(fiu->regmap, NPCM_FIU_DRD_CFG,
536ace55c41STomer Maimon NPCM_FIU_DRD_16_BYTE_BURST);
537ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
538ace55c41STomer Maimon NPCM_FIU_DRD_CFG_ACCTYPE,
539ace55c41STomer Maimon DRD_SPI_X_MODE << NPCM_FIU_DRD_ACCTYPE_SHIFT);
540ace55c41STomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
541ace55c41STomer Maimon NPCM_FIU_DRD_CFG_DBW,
542ace55c41STomer Maimon rx_dummy << NPCM_FIU_DRD_DBW_SHIFT);
543ace55c41STomer Maimon }
544ace55c41STomer Maimon
npcm_fiu_exec_op(struct spi_mem * mem,const struct spi_mem_op * op)545ace55c41STomer Maimon static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
546ace55c41STomer Maimon {
547ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
5481f6c80a7SYang Yingliang spi_controller_get_devdata(mem->spi->controller);
5499e264f3fSAmit Kumar Mahapatra via Alsa-devel struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(mem->spi, 0)];
550ace55c41STomer Maimon int ret = 0;
551ace55c41STomer Maimon u8 *buf;
552ace55c41STomer Maimon
553ace55c41STomer Maimon dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
554ace55c41STomer Maimon op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
555ace55c41STomer Maimon op->dummy.buswidth, op->data.buswidth, op->addr.val,
556ace55c41STomer Maimon op->data.nbytes);
557ace55c41STomer Maimon
558ace55c41STomer Maimon if (fiu->spix_mode || op->addr.nbytes > 4)
559ace55c41STomer Maimon return -ENOTSUPP;
560ace55c41STomer Maimon
561ace55c41STomer Maimon if (fiu->clkrate != chip->clkrate) {
562ace55c41STomer Maimon ret = clk_set_rate(fiu->clk, chip->clkrate);
563ace55c41STomer Maimon if (ret < 0)
5640d6fccc1SColin Ian King dev_warn(fiu->dev, "Failed setting %lu frequency, stay at %lu frequency\n",
5650d6fccc1SColin Ian King chip->clkrate, fiu->clkrate);
566ace55c41STomer Maimon else
567ace55c41STomer Maimon fiu->clkrate = chip->clkrate;
568ace55c41STomer Maimon }
569ace55c41STomer Maimon
570ace55c41STomer Maimon if (op->data.dir == SPI_MEM_DATA_IN) {
571ace55c41STomer Maimon if (!op->addr.nbytes) {
572ace55c41STomer Maimon buf = op->data.buf.in;
573ace55c41STomer Maimon ret = npcm_fiu_uma_read(mem, op, op->addr.val, false,
574ace55c41STomer Maimon buf, op->data.nbytes);
575ace55c41STomer Maimon } else {
576ace55c41STomer Maimon ret = npcm_fiu_read(mem, op);
577ace55c41STomer Maimon }
578ace55c41STomer Maimon } else {
579ace55c41STomer Maimon if (!op->addr.nbytes && !op->data.nbytes)
580ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
581ace55c41STomer Maimon NULL, 0);
582ace55c41STomer Maimon if (op->addr.nbytes && !op->data.nbytes) {
583ace55c41STomer Maimon int i;
584ace55c41STomer Maimon u8 buf_addr[4];
585ace55c41STomer Maimon u32 addr = op->addr.val;
586ace55c41STomer Maimon
587ace55c41STomer Maimon for (i = op->addr.nbytes - 1; i >= 0; i--) {
588ace55c41STomer Maimon buf_addr[i] = addr & 0xff;
589ace55c41STomer Maimon addr >>= 8;
590ace55c41STomer Maimon }
591ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
592ace55c41STomer Maimon buf_addr, op->addr.nbytes);
593ace55c41STomer Maimon }
594ace55c41STomer Maimon if (!op->addr.nbytes && op->data.nbytes)
595ace55c41STomer Maimon ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
596ace55c41STomer Maimon (u8 *)op->data.buf.out,
597ace55c41STomer Maimon op->data.nbytes);
598ace55c41STomer Maimon if (op->addr.nbytes && op->data.nbytes)
599ace55c41STomer Maimon ret = npcm_fiu_manualwrite(mem, op);
600ace55c41STomer Maimon }
601ace55c41STomer Maimon
602ace55c41STomer Maimon return ret;
603ace55c41STomer Maimon }
604ace55c41STomer Maimon
npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc * desc)605ace55c41STomer Maimon static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
606ace55c41STomer Maimon {
607ace55c41STomer Maimon struct npcm_fiu_spi *fiu =
6081f6c80a7SYang Yingliang spi_controller_get_devdata(desc->mem->spi->controller);
6099e264f3fSAmit Kumar Mahapatra via Alsa-devel struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
610ace55c41STomer Maimon struct regmap *gcr_regmap;
611ace55c41STomer Maimon
612ace55c41STomer Maimon if (!fiu->res_mem) {
613ace55c41STomer Maimon dev_warn(fiu->dev, "Reserved memory not defined, direct read disabled\n");
614ace55c41STomer Maimon desc->nodirmap = true;
615ace55c41STomer Maimon return 0;
616ace55c41STomer Maimon }
617ace55c41STomer Maimon
618ace55c41STomer Maimon if (!fiu->spix_mode &&
619ace55c41STomer Maimon desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
620ace55c41STomer Maimon desc->nodirmap = true;
621ace55c41STomer Maimon return 0;
622ace55c41STomer Maimon }
623ace55c41STomer Maimon
624ace55c41STomer Maimon if (!chip->flash_region_mapped_ptr) {
625ace55c41STomer Maimon chip->flash_region_mapped_ptr =
6264bdc0d67SChristoph Hellwig devm_ioremap(fiu->dev, (fiu->res_mem->start +
627ace55c41STomer Maimon (fiu->info->max_map_size *
6289e264f3fSAmit Kumar Mahapatra via Alsa-devel spi_get_chipselect(desc->mem->spi, 0))),
629ace55c41STomer Maimon (u32)desc->info.length);
630ace55c41STomer Maimon if (!chip->flash_region_mapped_ptr) {
631ace55c41STomer Maimon dev_warn(fiu->dev, "Error mapping memory region, direct read disabled\n");
632ace55c41STomer Maimon desc->nodirmap = true;
633ace55c41STomer Maimon return 0;
634ace55c41STomer Maimon }
635ace55c41STomer Maimon }
636ace55c41STomer Maimon
637ace55c41STomer Maimon if (of_device_is_compatible(fiu->dev->of_node, "nuvoton,npcm750-fiu")) {
638ace55c41STomer Maimon gcr_regmap =
639ace55c41STomer Maimon syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
640ace55c41STomer Maimon if (IS_ERR(gcr_regmap)) {
641ace55c41STomer Maimon dev_warn(fiu->dev, "Didn't find nuvoton,npcm750-gcr, direct read disabled\n");
642ace55c41STomer Maimon desc->nodirmap = true;
643ace55c41STomer Maimon return 0;
644ace55c41STomer Maimon }
645ace55c41STomer Maimon regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
646ace55c41STomer Maimon NPCM7XX_INTCR3_FIU_FIX,
647ace55c41STomer Maimon NPCM7XX_INTCR3_FIU_FIX);
648650b014fSTomer Maimon } else {
649650b014fSTomer Maimon regmap_update_bits(fiu->regmap, NPCM_FIU_CFG,
650650b014fSTomer Maimon NPCM_FIU_CFG_FIU_FIX,
651650b014fSTomer Maimon NPCM_FIU_CFG_FIU_FIX);
652ace55c41STomer Maimon }
653ace55c41STomer Maimon
654ace55c41STomer Maimon if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
655ace55c41STomer Maimon if (!fiu->spix_mode)
656ace55c41STomer Maimon npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
657ace55c41STomer Maimon else
658ace55c41STomer Maimon npcm_fiux_set_direct_rd(fiu);
659ace55c41STomer Maimon
660ace55c41STomer Maimon } else {
661ace55c41STomer Maimon npcm_fiux_set_direct_wr(fiu);
662ace55c41STomer Maimon }
663ace55c41STomer Maimon
664ace55c41STomer Maimon return 0;
665ace55c41STomer Maimon }
666ace55c41STomer Maimon
npcm_fiu_setup(struct spi_device * spi)667ace55c41STomer Maimon static int npcm_fiu_setup(struct spi_device *spi)
668ace55c41STomer Maimon {
6691f6c80a7SYang Yingliang struct spi_controller *ctrl = spi->controller;
670ace55c41STomer Maimon struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
671ace55c41STomer Maimon struct npcm_fiu_chip *chip;
672ace55c41STomer Maimon
6739e264f3fSAmit Kumar Mahapatra via Alsa-devel chip = &fiu->chip[spi_get_chipselect(spi, 0)];
674ace55c41STomer Maimon chip->fiu = fiu;
6759e264f3fSAmit Kumar Mahapatra via Alsa-devel chip->chipselect = spi_get_chipselect(spi, 0);
676ace55c41STomer Maimon chip->clkrate = spi->max_speed_hz;
677ace55c41STomer Maimon
678ace55c41STomer Maimon fiu->clkrate = clk_get_rate(fiu->clk);
679ace55c41STomer Maimon
680ace55c41STomer Maimon return 0;
681ace55c41STomer Maimon }
682ace55c41STomer Maimon
683ace55c41STomer Maimon static const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
684ace55c41STomer Maimon .exec_op = npcm_fiu_exec_op,
685ace55c41STomer Maimon .dirmap_create = npcm_fiu_dirmap_create,
686ace55c41STomer Maimon .dirmap_read = npcm_fiu_direct_read,
687ace55c41STomer Maimon .dirmap_write = npcm_fiu_direct_write,
688ace55c41STomer Maimon };
689ace55c41STomer Maimon
690ace55c41STomer Maimon static const struct of_device_id npcm_fiu_dt_ids[] = {
691b15e3bc7SJonathan Neuschäfer { .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data },
692650b014fSTomer Maimon { .compatible = "nuvoton,npcm845-fiu", .data = &npxm8xx_fiu_data },
693ace55c41STomer Maimon { /* sentinel */ }
694ace55c41STomer Maimon };
695ace55c41STomer Maimon
npcm_fiu_probe(struct platform_device * pdev)696ace55c41STomer Maimon static int npcm_fiu_probe(struct platform_device *pdev)
697ace55c41STomer Maimon {
698ace55c41STomer Maimon const struct fiu_data *fiu_data_match;
699ace55c41STomer Maimon struct device *dev = &pdev->dev;
700ace55c41STomer Maimon struct spi_controller *ctrl;
701ace55c41STomer Maimon struct npcm_fiu_spi *fiu;
702ace55c41STomer Maimon void __iomem *regbase;
703234266a5SLukas Wunner int id, ret;
704ace55c41STomer Maimon
7051f6c80a7SYang Yingliang ctrl = devm_spi_alloc_host(dev, sizeof(*fiu));
706ace55c41STomer Maimon if (!ctrl)
707ace55c41STomer Maimon return -ENOMEM;
708ace55c41STomer Maimon
709ace55c41STomer Maimon fiu = spi_controller_get_devdata(ctrl);
710ace55c41STomer Maimon
711dc8fea13SMinghao Chi (CGEL ZTE) fiu_data_match = of_device_get_match_data(dev);
712dc8fea13SMinghao Chi (CGEL ZTE) if (!fiu_data_match) {
713ace55c41STomer Maimon dev_err(dev, "No compatible OF match\n");
714ace55c41STomer Maimon return -ENODEV;
715ace55c41STomer Maimon }
716ace55c41STomer Maimon
717ace55c41STomer Maimon id = of_alias_get_id(dev->of_node, "fiu");
718ace55c41STomer Maimon if (id < 0 || id >= fiu_data_match->fiu_max) {
719ace55c41STomer Maimon dev_err(dev, "Invalid platform device id: %d\n", id);
720ace55c41STomer Maimon return -EINVAL;
721ace55c41STomer Maimon }
722ace55c41STomer Maimon
723ace55c41STomer Maimon fiu->info = &fiu_data_match->npcm_fiu_data_info[id];
724ace55c41STomer Maimon
725ace55c41STomer Maimon platform_set_drvdata(pdev, fiu);
726ace55c41STomer Maimon fiu->dev = dev;
727ace55c41STomer Maimon
7281793d366SYang Yingliang regbase = devm_platform_ioremap_resource_byname(pdev, "control");
729ace55c41STomer Maimon if (IS_ERR(regbase))
730ace55c41STomer Maimon return PTR_ERR(regbase);
731ace55c41STomer Maimon
732ace55c41STomer Maimon fiu->regmap = devm_regmap_init_mmio(dev, regbase,
733ace55c41STomer Maimon &npcm_mtd_regmap_config);
734ace55c41STomer Maimon if (IS_ERR(fiu->regmap)) {
735ace55c41STomer Maimon dev_err(dev, "Failed to create regmap\n");
736ace55c41STomer Maimon return PTR_ERR(fiu->regmap);
737ace55c41STomer Maimon }
738ace55c41STomer Maimon
739ace55c41STomer Maimon fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
740ace55c41STomer Maimon "memory");
741ace55c41STomer Maimon fiu->clk = devm_clk_get(dev, NULL);
742ace55c41STomer Maimon if (IS_ERR(fiu->clk))
743ace55c41STomer Maimon return PTR_ERR(fiu->clk);
744ace55c41STomer Maimon
745ace55c41STomer Maimon fiu->spix_mode = of_property_read_bool(dev->of_node,
746ace55c41STomer Maimon "nuvoton,spix-mode");
747ace55c41STomer Maimon
748ace55c41STomer Maimon platform_set_drvdata(pdev, fiu);
749ace55c41STomer Maimon clk_prepare_enable(fiu->clk);
750ace55c41STomer Maimon
751ace55c41STomer Maimon ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
752ace55c41STomer Maimon | SPI_TX_DUAL | SPI_TX_QUAD;
753ace55c41STomer Maimon ctrl->setup = npcm_fiu_setup;
754ace55c41STomer Maimon ctrl->bus_num = -1;
755ace55c41STomer Maimon ctrl->mem_ops = &npcm_fiu_mem_ops;
756ace55c41STomer Maimon ctrl->num_chipselect = fiu->info->max_cs;
757ace55c41STomer Maimon ctrl->dev.of_node = dev->of_node;
758ace55c41STomer Maimon
7591f6c80a7SYang Yingliang ret = devm_spi_register_controller(dev, ctrl);
760234266a5SLukas Wunner if (ret)
761234266a5SLukas Wunner clk_disable_unprepare(fiu->clk);
762234266a5SLukas Wunner
763234266a5SLukas Wunner return ret;
764ace55c41STomer Maimon }
765ace55c41STomer Maimon
npcm_fiu_remove(struct platform_device * pdev)7665e4830adSUwe Kleine-König static void npcm_fiu_remove(struct platform_device *pdev)
767ace55c41STomer Maimon {
768ace55c41STomer Maimon struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev);
769ace55c41STomer Maimon
770ace55c41STomer Maimon clk_disable_unprepare(fiu->clk);
771ace55c41STomer Maimon }
772ace55c41STomer Maimon
773ace55c41STomer Maimon MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids);
774ace55c41STomer Maimon
775ace55c41STomer Maimon static struct platform_driver npcm_fiu_driver = {
776ace55c41STomer Maimon .driver = {
777ace55c41STomer Maimon .name = "NPCM-FIU",
778ace55c41STomer Maimon .bus = &platform_bus_type,
779ace55c41STomer Maimon .of_match_table = npcm_fiu_dt_ids,
780ace55c41STomer Maimon },
781ace55c41STomer Maimon .probe = npcm_fiu_probe,
7825e4830adSUwe Kleine-König .remove_new = npcm_fiu_remove,
783ace55c41STomer Maimon };
784ace55c41STomer Maimon module_platform_driver(npcm_fiu_driver);
785ace55c41STomer Maimon
786ace55c41STomer Maimon MODULE_DESCRIPTION("Nuvoton FLASH Interface Unit SPI Controller Driver");
787ace55c41STomer Maimon MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
788ace55c41STomer Maimon MODULE_LICENSE("GPL v2");
789