xref: /openbmc/linux/drivers/pinctrl/renesas/core.c (revision 1e952e95843d437b8a904dbd5b48d72db8ac23ec)
1077365a9SGeert Uytterhoeven // SPDX-License-Identifier: GPL-2.0
2077365a9SGeert Uytterhoeven /*
3077365a9SGeert Uytterhoeven  * Pin Control and GPIO driver for SuperH Pin Function Controller.
4077365a9SGeert Uytterhoeven  *
5077365a9SGeert Uytterhoeven  * Authors: Magnus Damm, Paul Mundt, Laurent Pinchart
6077365a9SGeert Uytterhoeven  *
7077365a9SGeert Uytterhoeven  * Copyright (C) 2008 Magnus Damm
8077365a9SGeert Uytterhoeven  * Copyright (C) 2009 - 2012 Paul Mundt
9077365a9SGeert Uytterhoeven  */
10077365a9SGeert Uytterhoeven 
11077365a9SGeert Uytterhoeven #define DRV_NAME "sh-pfc"
12077365a9SGeert Uytterhoeven 
13077365a9SGeert Uytterhoeven #include <linux/bitops.h>
14077365a9SGeert Uytterhoeven #include <linux/err.h>
15077365a9SGeert Uytterhoeven #include <linux/errno.h>
1662109055SGeert Uytterhoeven #include <linux/init.h>
17077365a9SGeert Uytterhoeven #include <linux/io.h>
18077365a9SGeert Uytterhoeven #include <linux/ioport.h>
19077365a9SGeert Uytterhoeven #include <linux/kernel.h>
2062109055SGeert Uytterhoeven #include <linux/math.h>
21077365a9SGeert Uytterhoeven #include <linux/of.h>
22077365a9SGeert Uytterhoeven #include <linux/pinctrl/machine.h>
23077365a9SGeert Uytterhoeven #include <linux/platform_device.h>
24077365a9SGeert Uytterhoeven #include <linux/psci.h>
25077365a9SGeert Uytterhoeven #include <linux/slab.h>
26077365a9SGeert Uytterhoeven #include <linux/sys_soc.h>
27077365a9SGeert Uytterhoeven 
28077365a9SGeert Uytterhoeven #include "core.h"
29077365a9SGeert Uytterhoeven 
sh_pfc_map_resources(struct sh_pfc * pfc,struct platform_device * pdev)30077365a9SGeert Uytterhoeven static int sh_pfc_map_resources(struct sh_pfc *pfc,
31077365a9SGeert Uytterhoeven 				struct platform_device *pdev)
32077365a9SGeert Uytterhoeven {
33077365a9SGeert Uytterhoeven 	struct sh_pfc_window *windows;
34077365a9SGeert Uytterhoeven 	unsigned int *irqs = NULL;
35077365a9SGeert Uytterhoeven 	unsigned int num_windows;
36077365a9SGeert Uytterhoeven 	struct resource *res;
37077365a9SGeert Uytterhoeven 	unsigned int i;
38077365a9SGeert Uytterhoeven 	int num_irqs;
39077365a9SGeert Uytterhoeven 
40077365a9SGeert Uytterhoeven 	/* Count the MEM and IRQ resources. */
41077365a9SGeert Uytterhoeven 	for (num_windows = 0;; num_windows++) {
42077365a9SGeert Uytterhoeven 		res = platform_get_resource(pdev, IORESOURCE_MEM, num_windows);
43077365a9SGeert Uytterhoeven 		if (!res)
44077365a9SGeert Uytterhoeven 			break;
45077365a9SGeert Uytterhoeven 	}
46077365a9SGeert Uytterhoeven 	if (num_windows == 0)
47077365a9SGeert Uytterhoeven 		return -EINVAL;
48077365a9SGeert Uytterhoeven 
49077365a9SGeert Uytterhoeven 	num_irqs = platform_irq_count(pdev);
50077365a9SGeert Uytterhoeven 	if (num_irqs < 0)
51077365a9SGeert Uytterhoeven 		return num_irqs;
52077365a9SGeert Uytterhoeven 
53077365a9SGeert Uytterhoeven 	/* Allocate memory windows and IRQs arrays. */
54077365a9SGeert Uytterhoeven 	windows = devm_kcalloc(pfc->dev, num_windows, sizeof(*windows),
55077365a9SGeert Uytterhoeven 			       GFP_KERNEL);
56077365a9SGeert Uytterhoeven 	if (windows == NULL)
57077365a9SGeert Uytterhoeven 		return -ENOMEM;
58077365a9SGeert Uytterhoeven 
59077365a9SGeert Uytterhoeven 	pfc->num_windows = num_windows;
60077365a9SGeert Uytterhoeven 	pfc->windows = windows;
61077365a9SGeert Uytterhoeven 
62077365a9SGeert Uytterhoeven 	if (num_irqs) {
63077365a9SGeert Uytterhoeven 		irqs = devm_kcalloc(pfc->dev, num_irqs, sizeof(*irqs),
64077365a9SGeert Uytterhoeven 				    GFP_KERNEL);
65077365a9SGeert Uytterhoeven 		if (irqs == NULL)
66077365a9SGeert Uytterhoeven 			return -ENOMEM;
67077365a9SGeert Uytterhoeven 
68077365a9SGeert Uytterhoeven 		pfc->num_irqs = num_irqs;
69077365a9SGeert Uytterhoeven 		pfc->irqs = irqs;
70077365a9SGeert Uytterhoeven 	}
71077365a9SGeert Uytterhoeven 
72077365a9SGeert Uytterhoeven 	/* Fill them. */
73077365a9SGeert Uytterhoeven 	for (i = 0; i < num_windows; i++) {
745376e3d9SYang Yingliang 		windows->virt = devm_platform_get_and_ioremap_resource(pdev, i, &res);
75077365a9SGeert Uytterhoeven 		if (IS_ERR(windows->virt))
76077365a9SGeert Uytterhoeven 			return -ENOMEM;
775376e3d9SYang Yingliang 		windows->phys = res->start;
785376e3d9SYang Yingliang 		windows->size = resource_size(res);
79077365a9SGeert Uytterhoeven 		windows++;
80077365a9SGeert Uytterhoeven 	}
81077365a9SGeert Uytterhoeven 	for (i = 0; i < num_irqs; i++)
82077365a9SGeert Uytterhoeven 		*irqs++ = platform_get_irq(pdev, i);
83077365a9SGeert Uytterhoeven 
84077365a9SGeert Uytterhoeven 	return 0;
85077365a9SGeert Uytterhoeven }
86077365a9SGeert Uytterhoeven 
sh_pfc_phys_to_virt(struct sh_pfc * pfc,u32 reg)87077365a9SGeert Uytterhoeven static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc, u32 reg)
88077365a9SGeert Uytterhoeven {
89077365a9SGeert Uytterhoeven 	struct sh_pfc_window *window;
90077365a9SGeert Uytterhoeven 	phys_addr_t address = reg;
91077365a9SGeert Uytterhoeven 	unsigned int i;
92077365a9SGeert Uytterhoeven 
93077365a9SGeert Uytterhoeven 	/* scan through physical windows and convert address */
94077365a9SGeert Uytterhoeven 	for (i = 0; i < pfc->num_windows; i++) {
95077365a9SGeert Uytterhoeven 		window = pfc->windows + i;
96077365a9SGeert Uytterhoeven 
97077365a9SGeert Uytterhoeven 		if (address < window->phys)
98077365a9SGeert Uytterhoeven 			continue;
99077365a9SGeert Uytterhoeven 
100077365a9SGeert Uytterhoeven 		if (address >= (window->phys + window->size))
101077365a9SGeert Uytterhoeven 			continue;
102077365a9SGeert Uytterhoeven 
103077365a9SGeert Uytterhoeven 		return window->virt + (address - window->phys);
104077365a9SGeert Uytterhoeven 	}
105077365a9SGeert Uytterhoeven 
106077365a9SGeert Uytterhoeven 	BUG();
107077365a9SGeert Uytterhoeven 	return NULL;
108077365a9SGeert Uytterhoeven }
109077365a9SGeert Uytterhoeven 
sh_pfc_get_pin_index(struct sh_pfc * pfc,unsigned int pin)110077365a9SGeert Uytterhoeven int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin)
111077365a9SGeert Uytterhoeven {
112077365a9SGeert Uytterhoeven 	unsigned int offset;
113077365a9SGeert Uytterhoeven 	unsigned int i;
114077365a9SGeert Uytterhoeven 
115077365a9SGeert Uytterhoeven 	for (i = 0, offset = 0; i < pfc->nr_ranges; ++i) {
116077365a9SGeert Uytterhoeven 		const struct sh_pfc_pin_range *range = &pfc->ranges[i];
117077365a9SGeert Uytterhoeven 
118077365a9SGeert Uytterhoeven 		if (pin <= range->end)
119077365a9SGeert Uytterhoeven 			return pin >= range->start
120077365a9SGeert Uytterhoeven 			     ? offset + pin - range->start : -1;
121077365a9SGeert Uytterhoeven 
122077365a9SGeert Uytterhoeven 		offset += range->end - range->start + 1;
123077365a9SGeert Uytterhoeven 	}
124077365a9SGeert Uytterhoeven 
125077365a9SGeert Uytterhoeven 	return -EINVAL;
126077365a9SGeert Uytterhoeven }
127077365a9SGeert Uytterhoeven 
sh_pfc_enum_in_range(u16 enum_id,const struct pinmux_range * r)128077365a9SGeert Uytterhoeven static int sh_pfc_enum_in_range(u16 enum_id, const struct pinmux_range *r)
129077365a9SGeert Uytterhoeven {
130077365a9SGeert Uytterhoeven 	if (enum_id < r->begin)
131077365a9SGeert Uytterhoeven 		return 0;
132077365a9SGeert Uytterhoeven 
133077365a9SGeert Uytterhoeven 	if (enum_id > r->end)
134077365a9SGeert Uytterhoeven 		return 0;
135077365a9SGeert Uytterhoeven 
136077365a9SGeert Uytterhoeven 	return 1;
137077365a9SGeert Uytterhoeven }
138077365a9SGeert Uytterhoeven 
sh_pfc_read_raw_reg(void __iomem * mapped_reg,unsigned int reg_width)139077365a9SGeert Uytterhoeven u32 sh_pfc_read_raw_reg(void __iomem *mapped_reg, unsigned int reg_width)
140077365a9SGeert Uytterhoeven {
141077365a9SGeert Uytterhoeven 	switch (reg_width) {
142077365a9SGeert Uytterhoeven 	case 8:
143077365a9SGeert Uytterhoeven 		return ioread8(mapped_reg);
144077365a9SGeert Uytterhoeven 	case 16:
145077365a9SGeert Uytterhoeven 		return ioread16(mapped_reg);
146077365a9SGeert Uytterhoeven 	case 32:
147077365a9SGeert Uytterhoeven 		return ioread32(mapped_reg);
148077365a9SGeert Uytterhoeven 	}
149077365a9SGeert Uytterhoeven 
150077365a9SGeert Uytterhoeven 	BUG();
151077365a9SGeert Uytterhoeven 	return 0;
152077365a9SGeert Uytterhoeven }
153077365a9SGeert Uytterhoeven 
sh_pfc_write_raw_reg(void __iomem * mapped_reg,unsigned int reg_width,u32 data)154077365a9SGeert Uytterhoeven void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned int reg_width,
155077365a9SGeert Uytterhoeven 			  u32 data)
156077365a9SGeert Uytterhoeven {
157077365a9SGeert Uytterhoeven 	switch (reg_width) {
158077365a9SGeert Uytterhoeven 	case 8:
159077365a9SGeert Uytterhoeven 		iowrite8(data, mapped_reg);
160077365a9SGeert Uytterhoeven 		return;
161077365a9SGeert Uytterhoeven 	case 16:
162077365a9SGeert Uytterhoeven 		iowrite16(data, mapped_reg);
163077365a9SGeert Uytterhoeven 		return;
164077365a9SGeert Uytterhoeven 	case 32:
165077365a9SGeert Uytterhoeven 		iowrite32(data, mapped_reg);
166077365a9SGeert Uytterhoeven 		return;
167077365a9SGeert Uytterhoeven 	}
168077365a9SGeert Uytterhoeven 
169077365a9SGeert Uytterhoeven 	BUG();
170077365a9SGeert Uytterhoeven }
171077365a9SGeert Uytterhoeven 
sh_pfc_read(struct sh_pfc * pfc,u32 reg)172077365a9SGeert Uytterhoeven u32 sh_pfc_read(struct sh_pfc *pfc, u32 reg)
173077365a9SGeert Uytterhoeven {
174077365a9SGeert Uytterhoeven 	return sh_pfc_read_raw_reg(sh_pfc_phys_to_virt(pfc, reg), 32);
175077365a9SGeert Uytterhoeven }
176077365a9SGeert Uytterhoeven 
sh_pfc_unlock_reg(struct sh_pfc * pfc,u32 reg,u32 data)177e127ef2eSUlrich Hecht static void sh_pfc_unlock_reg(struct sh_pfc *pfc, u32 reg, u32 data)
178e127ef2eSUlrich Hecht {
179e127ef2eSUlrich Hecht 	u32 unlock;
180e127ef2eSUlrich Hecht 
181e127ef2eSUlrich Hecht 	if (!pfc->info->unlock_reg)
182e127ef2eSUlrich Hecht 		return;
183e127ef2eSUlrich Hecht 
184e127ef2eSUlrich Hecht 	if (pfc->info->unlock_reg >= 0x80000000UL)
185e127ef2eSUlrich Hecht 		unlock = pfc->info->unlock_reg;
186e127ef2eSUlrich Hecht 	else
187e127ef2eSUlrich Hecht 		/* unlock_reg is a mask */
188e127ef2eSUlrich Hecht 		unlock = reg & ~pfc->info->unlock_reg;
189e127ef2eSUlrich Hecht 
190e127ef2eSUlrich Hecht 	sh_pfc_write_raw_reg(sh_pfc_phys_to_virt(pfc, unlock), 32, ~data);
191e127ef2eSUlrich Hecht }
192e127ef2eSUlrich Hecht 
sh_pfc_write(struct sh_pfc * pfc,u32 reg,u32 data)193077365a9SGeert Uytterhoeven void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data)
194077365a9SGeert Uytterhoeven {
195e127ef2eSUlrich Hecht 	sh_pfc_unlock_reg(pfc, reg, data);
196077365a9SGeert Uytterhoeven 	sh_pfc_write_raw_reg(sh_pfc_phys_to_virt(pfc, reg), 32, data);
197077365a9SGeert Uytterhoeven }
198077365a9SGeert Uytterhoeven 
sh_pfc_config_reg_helper(struct sh_pfc * pfc,const struct pinmux_cfg_reg * crp,unsigned int in_pos,void __iomem ** mapped_regp,u32 * maskp,unsigned int * posp)199077365a9SGeert Uytterhoeven static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
200077365a9SGeert Uytterhoeven 				     const struct pinmux_cfg_reg *crp,
201077365a9SGeert Uytterhoeven 				     unsigned int in_pos,
202077365a9SGeert Uytterhoeven 				     void __iomem **mapped_regp, u32 *maskp,
203077365a9SGeert Uytterhoeven 				     unsigned int *posp)
204077365a9SGeert Uytterhoeven {
205077365a9SGeert Uytterhoeven 	unsigned int k;
206077365a9SGeert Uytterhoeven 
207077365a9SGeert Uytterhoeven 	*mapped_regp = sh_pfc_phys_to_virt(pfc, crp->reg);
208077365a9SGeert Uytterhoeven 
209077365a9SGeert Uytterhoeven 	if (crp->field_width) {
210077365a9SGeert Uytterhoeven 		*maskp = (1 << crp->field_width) - 1;
211077365a9SGeert Uytterhoeven 		*posp = crp->reg_width - ((in_pos + 1) * crp->field_width);
212077365a9SGeert Uytterhoeven 	} else {
213077365a9SGeert Uytterhoeven 		*maskp = (1 << crp->var_field_width[in_pos]) - 1;
214077365a9SGeert Uytterhoeven 		*posp = crp->reg_width;
215077365a9SGeert Uytterhoeven 		for (k = 0; k <= in_pos; k++)
21662109055SGeert Uytterhoeven 			*posp -= abs(crp->var_field_width[k]);
217077365a9SGeert Uytterhoeven 	}
218077365a9SGeert Uytterhoeven }
219077365a9SGeert Uytterhoeven 
sh_pfc_write_config_reg(struct sh_pfc * pfc,const struct pinmux_cfg_reg * crp,unsigned int field,u32 value)220077365a9SGeert Uytterhoeven static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
221077365a9SGeert Uytterhoeven 				    const struct pinmux_cfg_reg *crp,
222077365a9SGeert Uytterhoeven 				    unsigned int field, u32 value)
223077365a9SGeert Uytterhoeven {
224077365a9SGeert Uytterhoeven 	void __iomem *mapped_reg;
225077365a9SGeert Uytterhoeven 	unsigned int pos;
226077365a9SGeert Uytterhoeven 	u32 mask, data;
227077365a9SGeert Uytterhoeven 
228077365a9SGeert Uytterhoeven 	sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
229077365a9SGeert Uytterhoeven 
230077365a9SGeert Uytterhoeven 	dev_dbg(pfc->dev, "write_reg addr = %x, value = 0x%x, field = %u, "
231077365a9SGeert Uytterhoeven 		"r_width = %u, f_width = %u\n",
232077365a9SGeert Uytterhoeven 		crp->reg, value, field, crp->reg_width, hweight32(mask));
233077365a9SGeert Uytterhoeven 
234077365a9SGeert Uytterhoeven 	mask = ~(mask << pos);
235077365a9SGeert Uytterhoeven 	value = value << pos;
236077365a9SGeert Uytterhoeven 
237077365a9SGeert Uytterhoeven 	data = sh_pfc_read_raw_reg(mapped_reg, crp->reg_width);
238077365a9SGeert Uytterhoeven 	data &= mask;
239077365a9SGeert Uytterhoeven 	data |= value;
240077365a9SGeert Uytterhoeven 
241e127ef2eSUlrich Hecht 	sh_pfc_unlock_reg(pfc, crp->reg, data);
242077365a9SGeert Uytterhoeven 	sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
243077365a9SGeert Uytterhoeven }
244077365a9SGeert Uytterhoeven 
sh_pfc_get_config_reg(struct sh_pfc * pfc,u16 enum_id,const struct pinmux_cfg_reg ** crp,unsigned int * fieldp,u32 * valuep)245077365a9SGeert Uytterhoeven static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
246077365a9SGeert Uytterhoeven 				 const struct pinmux_cfg_reg **crp,
247077365a9SGeert Uytterhoeven 				 unsigned int *fieldp, u32 *valuep)
248077365a9SGeert Uytterhoeven {
249077365a9SGeert Uytterhoeven 	unsigned int k = 0;
250077365a9SGeert Uytterhoeven 
251077365a9SGeert Uytterhoeven 	while (1) {
252077365a9SGeert Uytterhoeven 		const struct pinmux_cfg_reg *config_reg =
253077365a9SGeert Uytterhoeven 			pfc->info->cfg_regs + k;
254077365a9SGeert Uytterhoeven 		unsigned int r_width = config_reg->reg_width;
255077365a9SGeert Uytterhoeven 		unsigned int f_width = config_reg->field_width;
256077365a9SGeert Uytterhoeven 		unsigned int curr_width;
257077365a9SGeert Uytterhoeven 		unsigned int bit_pos;
258077365a9SGeert Uytterhoeven 		unsigned int pos = 0;
259077365a9SGeert Uytterhoeven 		unsigned int m = 0;
260077365a9SGeert Uytterhoeven 
261077365a9SGeert Uytterhoeven 		if (!r_width)
262077365a9SGeert Uytterhoeven 			break;
263077365a9SGeert Uytterhoeven 
26462109055SGeert Uytterhoeven 		for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width, m++) {
265077365a9SGeert Uytterhoeven 			u32 ncomb;
266077365a9SGeert Uytterhoeven 			u32 n;
267077365a9SGeert Uytterhoeven 
26862109055SGeert Uytterhoeven 			if (f_width) {
269077365a9SGeert Uytterhoeven 				curr_width = f_width;
27062109055SGeert Uytterhoeven 			} else {
27162109055SGeert Uytterhoeven 				curr_width = abs(config_reg->var_field_width[m]);
27262109055SGeert Uytterhoeven 				if (config_reg->var_field_width[m] < 0)
27362109055SGeert Uytterhoeven 					continue;
27462109055SGeert Uytterhoeven 			}
275077365a9SGeert Uytterhoeven 
276077365a9SGeert Uytterhoeven 			ncomb = 1 << curr_width;
277077365a9SGeert Uytterhoeven 			for (n = 0; n < ncomb; n++) {
278077365a9SGeert Uytterhoeven 				if (config_reg->enum_ids[pos + n] == enum_id) {
279077365a9SGeert Uytterhoeven 					*crp = config_reg;
280077365a9SGeert Uytterhoeven 					*fieldp = m;
281077365a9SGeert Uytterhoeven 					*valuep = n;
282077365a9SGeert Uytterhoeven 					return 0;
283077365a9SGeert Uytterhoeven 				}
284077365a9SGeert Uytterhoeven 			}
285077365a9SGeert Uytterhoeven 			pos += ncomb;
286077365a9SGeert Uytterhoeven 		}
287077365a9SGeert Uytterhoeven 		k++;
288077365a9SGeert Uytterhoeven 	}
289077365a9SGeert Uytterhoeven 
290077365a9SGeert Uytterhoeven 	return -EINVAL;
291077365a9SGeert Uytterhoeven }
292077365a9SGeert Uytterhoeven 
sh_pfc_mark_to_enum(struct sh_pfc * pfc,u16 mark,int pos,u16 * enum_idp)293077365a9SGeert Uytterhoeven static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, u16 mark, int pos,
294077365a9SGeert Uytterhoeven 			      u16 *enum_idp)
295077365a9SGeert Uytterhoeven {
296077365a9SGeert Uytterhoeven 	const u16 *data = pfc->info->pinmux_data;
297077365a9SGeert Uytterhoeven 	unsigned int k;
298077365a9SGeert Uytterhoeven 
299077365a9SGeert Uytterhoeven 	if (pos) {
300077365a9SGeert Uytterhoeven 		*enum_idp = data[pos + 1];
301077365a9SGeert Uytterhoeven 		return pos + 1;
302077365a9SGeert Uytterhoeven 	}
303077365a9SGeert Uytterhoeven 
304077365a9SGeert Uytterhoeven 	for (k = 0; k < pfc->info->pinmux_data_size; k++) {
305077365a9SGeert Uytterhoeven 		if (data[k] == mark) {
306077365a9SGeert Uytterhoeven 			*enum_idp = data[k + 1];
307077365a9SGeert Uytterhoeven 			return k + 1;
308077365a9SGeert Uytterhoeven 		}
309077365a9SGeert Uytterhoeven 	}
310077365a9SGeert Uytterhoeven 
311077365a9SGeert Uytterhoeven 	dev_err(pfc->dev, "cannot locate data/mark enum_id for mark %d\n",
312077365a9SGeert Uytterhoeven 		mark);
313077365a9SGeert Uytterhoeven 	return -EINVAL;
314077365a9SGeert Uytterhoeven }
315077365a9SGeert Uytterhoeven 
sh_pfc_config_mux(struct sh_pfc * pfc,unsigned mark,int pinmux_type)316077365a9SGeert Uytterhoeven int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
317077365a9SGeert Uytterhoeven {
318077365a9SGeert Uytterhoeven 	const struct pinmux_range *range;
319077365a9SGeert Uytterhoeven 	int pos = 0;
320077365a9SGeert Uytterhoeven 
321077365a9SGeert Uytterhoeven 	switch (pinmux_type) {
322077365a9SGeert Uytterhoeven 	case PINMUX_TYPE_GPIO:
323077365a9SGeert Uytterhoeven 	case PINMUX_TYPE_FUNCTION:
324077365a9SGeert Uytterhoeven 		range = NULL;
325077365a9SGeert Uytterhoeven 		break;
326077365a9SGeert Uytterhoeven 
3277b1425f0SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_SH_PFC_GPIO
328077365a9SGeert Uytterhoeven 	case PINMUX_TYPE_OUTPUT:
329077365a9SGeert Uytterhoeven 		range = &pfc->info->output;
330077365a9SGeert Uytterhoeven 		break;
331077365a9SGeert Uytterhoeven 
332077365a9SGeert Uytterhoeven 	case PINMUX_TYPE_INPUT:
333077365a9SGeert Uytterhoeven 		range = &pfc->info->input;
334077365a9SGeert Uytterhoeven 		break;
3357b1425f0SGeert Uytterhoeven #endif /* CONFIG_PINCTRL_SH_PFC_GPIO */
336077365a9SGeert Uytterhoeven 
337077365a9SGeert Uytterhoeven 	default:
338077365a9SGeert Uytterhoeven 		return -EINVAL;
339077365a9SGeert Uytterhoeven 	}
340077365a9SGeert Uytterhoeven 
341077365a9SGeert Uytterhoeven 	/* Iterate over all the configuration fields we need to update. */
342077365a9SGeert Uytterhoeven 	while (1) {
343077365a9SGeert Uytterhoeven 		const struct pinmux_cfg_reg *cr;
344077365a9SGeert Uytterhoeven 		unsigned int field;
345077365a9SGeert Uytterhoeven 		u16 enum_id;
346077365a9SGeert Uytterhoeven 		u32 value;
347077365a9SGeert Uytterhoeven 		int in_range;
348077365a9SGeert Uytterhoeven 		int ret;
349077365a9SGeert Uytterhoeven 
350077365a9SGeert Uytterhoeven 		pos = sh_pfc_mark_to_enum(pfc, mark, pos, &enum_id);
351077365a9SGeert Uytterhoeven 		if (pos < 0)
352077365a9SGeert Uytterhoeven 			return pos;
353077365a9SGeert Uytterhoeven 
354077365a9SGeert Uytterhoeven 		if (!enum_id)
355077365a9SGeert Uytterhoeven 			break;
356077365a9SGeert Uytterhoeven 
357077365a9SGeert Uytterhoeven 		/* Check if the configuration field selects a function. If it
358077365a9SGeert Uytterhoeven 		 * doesn't, skip the field if it's not applicable to the
359077365a9SGeert Uytterhoeven 		 * requested pinmux type.
360077365a9SGeert Uytterhoeven 		 */
361077365a9SGeert Uytterhoeven 		in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->function);
362077365a9SGeert Uytterhoeven 		if (!in_range) {
363077365a9SGeert Uytterhoeven 			if (pinmux_type == PINMUX_TYPE_FUNCTION) {
364077365a9SGeert Uytterhoeven 				/* Functions are allowed to modify all
365077365a9SGeert Uytterhoeven 				 * fields.
366077365a9SGeert Uytterhoeven 				 */
367077365a9SGeert Uytterhoeven 				in_range = 1;
368077365a9SGeert Uytterhoeven 			} else if (pinmux_type != PINMUX_TYPE_GPIO) {
369077365a9SGeert Uytterhoeven 				/* Input/output types can only modify fields
370077365a9SGeert Uytterhoeven 				 * that correspond to their respective ranges.
371077365a9SGeert Uytterhoeven 				 */
372077365a9SGeert Uytterhoeven 				in_range = sh_pfc_enum_in_range(enum_id, range);
373077365a9SGeert Uytterhoeven 
374077365a9SGeert Uytterhoeven 				/*
375077365a9SGeert Uytterhoeven 				 * special case pass through for fixed
376077365a9SGeert Uytterhoeven 				 * input-only or output-only pins without
377077365a9SGeert Uytterhoeven 				 * function enum register association.
378077365a9SGeert Uytterhoeven 				 */
379077365a9SGeert Uytterhoeven 				if (in_range && enum_id == range->force)
380077365a9SGeert Uytterhoeven 					continue;
381077365a9SGeert Uytterhoeven 			}
382077365a9SGeert Uytterhoeven 			/* GPIOs are only allowed to modify function fields. */
383077365a9SGeert Uytterhoeven 		}
384077365a9SGeert Uytterhoeven 
385077365a9SGeert Uytterhoeven 		if (!in_range)
386077365a9SGeert Uytterhoeven 			continue;
387077365a9SGeert Uytterhoeven 
388077365a9SGeert Uytterhoeven 		ret = sh_pfc_get_config_reg(pfc, enum_id, &cr, &field, &value);
389077365a9SGeert Uytterhoeven 		if (ret < 0)
390077365a9SGeert Uytterhoeven 			return ret;
391077365a9SGeert Uytterhoeven 
392077365a9SGeert Uytterhoeven 		sh_pfc_write_config_reg(pfc, cr, field, value);
393077365a9SGeert Uytterhoeven 	}
394077365a9SGeert Uytterhoeven 
395077365a9SGeert Uytterhoeven 	return 0;
396077365a9SGeert Uytterhoeven }
397077365a9SGeert Uytterhoeven 
sh_pfc_init_ranges(struct sh_pfc * pfc)398077365a9SGeert Uytterhoeven static int sh_pfc_init_ranges(struct sh_pfc *pfc)
399077365a9SGeert Uytterhoeven {
400077365a9SGeert Uytterhoeven 	struct sh_pfc_pin_range *range;
401077365a9SGeert Uytterhoeven 	unsigned int nr_ranges;
402077365a9SGeert Uytterhoeven 	unsigned int i;
403077365a9SGeert Uytterhoeven 
404077365a9SGeert Uytterhoeven 	if (pfc->info->pins[0].pin == (u16)-1) {
405077365a9SGeert Uytterhoeven 		/* Pin number -1 denotes that the SoC doesn't report pin numbers
406077365a9SGeert Uytterhoeven 		 * in its pin arrays yet. Consider the pin numbers range as
407077365a9SGeert Uytterhoeven 		 * continuous and allocate a single range.
408077365a9SGeert Uytterhoeven 		 */
409077365a9SGeert Uytterhoeven 		pfc->nr_ranges = 1;
410077365a9SGeert Uytterhoeven 		pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges),
411077365a9SGeert Uytterhoeven 					   GFP_KERNEL);
412077365a9SGeert Uytterhoeven 		if (pfc->ranges == NULL)
413077365a9SGeert Uytterhoeven 			return -ENOMEM;
414077365a9SGeert Uytterhoeven 
415077365a9SGeert Uytterhoeven 		pfc->ranges->start = 0;
416077365a9SGeert Uytterhoeven 		pfc->ranges->end = pfc->info->nr_pins - 1;
417077365a9SGeert Uytterhoeven 		pfc->nr_gpio_pins = pfc->info->nr_pins;
418077365a9SGeert Uytterhoeven 
419077365a9SGeert Uytterhoeven 		return 0;
420077365a9SGeert Uytterhoeven 	}
421077365a9SGeert Uytterhoeven 
422077365a9SGeert Uytterhoeven 	/* Count, allocate and fill the ranges. The PFC SoC data pins array must
423077365a9SGeert Uytterhoeven 	 * be sorted by pin numbers, and pins without a GPIO port must come
424077365a9SGeert Uytterhoeven 	 * last.
425077365a9SGeert Uytterhoeven 	 */
426077365a9SGeert Uytterhoeven 	for (i = 1, nr_ranges = 1; i < pfc->info->nr_pins; ++i) {
427077365a9SGeert Uytterhoeven 		if (pfc->info->pins[i-1].pin != pfc->info->pins[i].pin - 1)
428077365a9SGeert Uytterhoeven 			nr_ranges++;
429077365a9SGeert Uytterhoeven 	}
430077365a9SGeert Uytterhoeven 
431077365a9SGeert Uytterhoeven 	pfc->nr_ranges = nr_ranges;
432077365a9SGeert Uytterhoeven 	pfc->ranges = devm_kcalloc(pfc->dev, nr_ranges, sizeof(*pfc->ranges),
433077365a9SGeert Uytterhoeven 				   GFP_KERNEL);
434077365a9SGeert Uytterhoeven 	if (pfc->ranges == NULL)
435077365a9SGeert Uytterhoeven 		return -ENOMEM;
436077365a9SGeert Uytterhoeven 
437077365a9SGeert Uytterhoeven 	range = pfc->ranges;
438077365a9SGeert Uytterhoeven 	range->start = pfc->info->pins[0].pin;
439077365a9SGeert Uytterhoeven 
440077365a9SGeert Uytterhoeven 	for (i = 1; i < pfc->info->nr_pins; ++i) {
441077365a9SGeert Uytterhoeven 		if (pfc->info->pins[i-1].pin == pfc->info->pins[i].pin - 1)
442077365a9SGeert Uytterhoeven 			continue;
443077365a9SGeert Uytterhoeven 
444077365a9SGeert Uytterhoeven 		range->end = pfc->info->pins[i-1].pin;
445077365a9SGeert Uytterhoeven 		if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
446077365a9SGeert Uytterhoeven 			pfc->nr_gpio_pins = range->end + 1;
447077365a9SGeert Uytterhoeven 
448077365a9SGeert Uytterhoeven 		range++;
449077365a9SGeert Uytterhoeven 		range->start = pfc->info->pins[i].pin;
450077365a9SGeert Uytterhoeven 	}
451077365a9SGeert Uytterhoeven 
452077365a9SGeert Uytterhoeven 	range->end = pfc->info->pins[i-1].pin;
453077365a9SGeert Uytterhoeven 	if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
454077365a9SGeert Uytterhoeven 		pfc->nr_gpio_pins = range->end + 1;
455077365a9SGeert Uytterhoeven 
456077365a9SGeert Uytterhoeven 	return 0;
457077365a9SGeert Uytterhoeven }
458077365a9SGeert Uytterhoeven 
459077365a9SGeert Uytterhoeven #ifdef CONFIG_OF
460077365a9SGeert Uytterhoeven static const struct of_device_id sh_pfc_of_table[] = {
461077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_EMEV2
462077365a9SGeert Uytterhoeven 	{
463077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-emev2",
464077365a9SGeert Uytterhoeven 		.data = &emev2_pinmux_info,
465077365a9SGeert Uytterhoeven 	},
466077365a9SGeert Uytterhoeven #endif
467077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A73A4
468077365a9SGeert Uytterhoeven 	{
469077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a73a4",
470077365a9SGeert Uytterhoeven 		.data = &r8a73a4_pinmux_info,
471077365a9SGeert Uytterhoeven 	},
472077365a9SGeert Uytterhoeven #endif
473077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7740
474077365a9SGeert Uytterhoeven 	{
475077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7740",
476077365a9SGeert Uytterhoeven 		.data = &r8a7740_pinmux_info,
477077365a9SGeert Uytterhoeven 	},
478077365a9SGeert Uytterhoeven #endif
479077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7742
480077365a9SGeert Uytterhoeven 	{
481077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7742",
482077365a9SGeert Uytterhoeven 		.data = &r8a7742_pinmux_info,
483077365a9SGeert Uytterhoeven 	},
484077365a9SGeert Uytterhoeven #endif
485077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7743
486077365a9SGeert Uytterhoeven 	{
487077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7743",
488077365a9SGeert Uytterhoeven 		.data = &r8a7743_pinmux_info,
489077365a9SGeert Uytterhoeven 	},
490077365a9SGeert Uytterhoeven #endif
491077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7744
492077365a9SGeert Uytterhoeven 	{
493077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7744",
494077365a9SGeert Uytterhoeven 		.data = &r8a7744_pinmux_info,
495077365a9SGeert Uytterhoeven 	},
496077365a9SGeert Uytterhoeven #endif
497077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7745
498077365a9SGeert Uytterhoeven 	{
499077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7745",
500077365a9SGeert Uytterhoeven 		.data = &r8a7745_pinmux_info,
501077365a9SGeert Uytterhoeven 	},
502077365a9SGeert Uytterhoeven #endif
503077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77470
504077365a9SGeert Uytterhoeven 	{
505077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77470",
506077365a9SGeert Uytterhoeven 		.data = &r8a77470_pinmux_info,
507077365a9SGeert Uytterhoeven 	},
508077365a9SGeert Uytterhoeven #endif
509077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A774A1
510077365a9SGeert Uytterhoeven 	{
511077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a774a1",
512077365a9SGeert Uytterhoeven 		.data = &r8a774a1_pinmux_info,
513077365a9SGeert Uytterhoeven 	},
514077365a9SGeert Uytterhoeven #endif
515077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A774B1
516077365a9SGeert Uytterhoeven 	{
517077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a774b1",
518077365a9SGeert Uytterhoeven 		.data = &r8a774b1_pinmux_info,
519077365a9SGeert Uytterhoeven 	},
520077365a9SGeert Uytterhoeven #endif
521077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A774C0
522077365a9SGeert Uytterhoeven 	{
523077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a774c0",
524077365a9SGeert Uytterhoeven 		.data = &r8a774c0_pinmux_info,
525077365a9SGeert Uytterhoeven 	},
526077365a9SGeert Uytterhoeven #endif
527077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A774E1
528077365a9SGeert Uytterhoeven 	{
529077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a774e1",
530077365a9SGeert Uytterhoeven 		.data = &r8a774e1_pinmux_info,
531077365a9SGeert Uytterhoeven 	},
532077365a9SGeert Uytterhoeven #endif
533077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7778
534077365a9SGeert Uytterhoeven 	{
535077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7778",
536077365a9SGeert Uytterhoeven 		.data = &r8a7778_pinmux_info,
537077365a9SGeert Uytterhoeven 	},
538077365a9SGeert Uytterhoeven #endif
539077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7779
540077365a9SGeert Uytterhoeven 	{
541077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7779",
542077365a9SGeert Uytterhoeven 		.data = &r8a7779_pinmux_info,
543077365a9SGeert Uytterhoeven 	},
544077365a9SGeert Uytterhoeven #endif
545077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7790
546077365a9SGeert Uytterhoeven 	{
547077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7790",
548077365a9SGeert Uytterhoeven 		.data = &r8a7790_pinmux_info,
549077365a9SGeert Uytterhoeven 	},
550077365a9SGeert Uytterhoeven #endif
551077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7791
552077365a9SGeert Uytterhoeven 	{
553077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7791",
554077365a9SGeert Uytterhoeven 		.data = &r8a7791_pinmux_info,
555077365a9SGeert Uytterhoeven 	},
556077365a9SGeert Uytterhoeven #endif
557077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7792
558077365a9SGeert Uytterhoeven 	{
559077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7792",
560077365a9SGeert Uytterhoeven 		.data = &r8a7792_pinmux_info,
561077365a9SGeert Uytterhoeven 	},
562077365a9SGeert Uytterhoeven #endif
563077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7793
564077365a9SGeert Uytterhoeven 	{
565077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7793",
566077365a9SGeert Uytterhoeven 		.data = &r8a7793_pinmux_info,
567077365a9SGeert Uytterhoeven 	},
568077365a9SGeert Uytterhoeven #endif
569077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A7794
570077365a9SGeert Uytterhoeven 	{
571077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7794",
572077365a9SGeert Uytterhoeven 		.data = &r8a7794_pinmux_info,
573077365a9SGeert Uytterhoeven 	},
574077365a9SGeert Uytterhoeven #endif
575077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77951
576077365a9SGeert Uytterhoeven 	{
577077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7795",
578077365a9SGeert Uytterhoeven 		.data = &r8a77951_pinmux_info,
579077365a9SGeert Uytterhoeven 	},
580077365a9SGeert Uytterhoeven #endif
581077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77960
582077365a9SGeert Uytterhoeven 	{
583077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a7796",
584077365a9SGeert Uytterhoeven 		.data = &r8a77960_pinmux_info,
585077365a9SGeert Uytterhoeven 	},
586077365a9SGeert Uytterhoeven #endif
587077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77961
588077365a9SGeert Uytterhoeven 	{
589077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77961",
590077365a9SGeert Uytterhoeven 		.data = &r8a77961_pinmux_info,
591077365a9SGeert Uytterhoeven 	},
592077365a9SGeert Uytterhoeven #endif
593077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77965
594077365a9SGeert Uytterhoeven 	{
595077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77965",
596077365a9SGeert Uytterhoeven 		.data = &r8a77965_pinmux_info,
597077365a9SGeert Uytterhoeven 	},
598077365a9SGeert Uytterhoeven #endif
599077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77970
600077365a9SGeert Uytterhoeven 	{
601077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77970",
602077365a9SGeert Uytterhoeven 		.data = &r8a77970_pinmux_info,
603077365a9SGeert Uytterhoeven 	},
604077365a9SGeert Uytterhoeven #endif
605077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77980
606077365a9SGeert Uytterhoeven 	{
607077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77980",
608077365a9SGeert Uytterhoeven 		.data = &r8a77980_pinmux_info,
609077365a9SGeert Uytterhoeven 	},
610077365a9SGeert Uytterhoeven #endif
611077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77990
612077365a9SGeert Uytterhoeven 	{
613077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77990",
614077365a9SGeert Uytterhoeven 		.data = &r8a77990_pinmux_info,
615077365a9SGeert Uytterhoeven 	},
616077365a9SGeert Uytterhoeven #endif
617077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A77995
618077365a9SGeert Uytterhoeven 	{
619077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a77995",
620077365a9SGeert Uytterhoeven 		.data = &r8a77995_pinmux_info,
621077365a9SGeert Uytterhoeven 	},
622077365a9SGeert Uytterhoeven #endif
623741a7370SUlrich Hecht #ifdef CONFIG_PINCTRL_PFC_R8A779A0
624741a7370SUlrich Hecht 	{
625741a7370SUlrich Hecht 		.compatible = "renesas,pfc-r8a779a0",
626741a7370SUlrich Hecht 		.data = &r8a779a0_pinmux_info,
627741a7370SUlrich Hecht 	},
628741a7370SUlrich Hecht #endif
629030ac6d7SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_R8A779F0
630030ac6d7SGeert Uytterhoeven 	{
631030ac6d7SGeert Uytterhoeven 		.compatible = "renesas,pfc-r8a779f0",
632030ac6d7SGeert Uytterhoeven 		.data = &r8a779f0_pinmux_info,
633030ac6d7SGeert Uytterhoeven 	},
634030ac6d7SGeert Uytterhoeven #endif
635ad9bb2feSLUU HOAI #ifdef CONFIG_PINCTRL_PFC_R8A779G0
636ad9bb2feSLUU HOAI 	{
637ad9bb2feSLUU HOAI 		.compatible = "renesas,pfc-r8a779g0",
638ad9bb2feSLUU HOAI 		.data = &r8a779g0_pinmux_info,
639ad9bb2feSLUU HOAI 	},
640ad9bb2feSLUU HOAI #endif
641077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH73A0
642077365a9SGeert Uytterhoeven 	{
643077365a9SGeert Uytterhoeven 		.compatible = "renesas,pfc-sh73a0",
644077365a9SGeert Uytterhoeven 		.data = &sh73a0_pinmux_info,
645077365a9SGeert Uytterhoeven 	},
646077365a9SGeert Uytterhoeven #endif
6470256b6aeSGeert Uytterhoeven 	{ /* sentinel */ }
648077365a9SGeert Uytterhoeven };
649077365a9SGeert Uytterhoeven #endif
650077365a9SGeert Uytterhoeven 
651727eb02eSAndy Shevchenko #if defined(CONFIG_ARM_PSCI_FW)
sh_pfc_nop_reg(struct sh_pfc * pfc,u32 reg,unsigned int idx)652077365a9SGeert Uytterhoeven static void sh_pfc_nop_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
653077365a9SGeert Uytterhoeven {
654077365a9SGeert Uytterhoeven }
655077365a9SGeert Uytterhoeven 
sh_pfc_save_reg(struct sh_pfc * pfc,u32 reg,unsigned int idx)656077365a9SGeert Uytterhoeven static void sh_pfc_save_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
657077365a9SGeert Uytterhoeven {
658077365a9SGeert Uytterhoeven 	pfc->saved_regs[idx] = sh_pfc_read(pfc, reg);
659077365a9SGeert Uytterhoeven }
660077365a9SGeert Uytterhoeven 
sh_pfc_restore_reg(struct sh_pfc * pfc,u32 reg,unsigned int idx)661077365a9SGeert Uytterhoeven static void sh_pfc_restore_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
662077365a9SGeert Uytterhoeven {
663077365a9SGeert Uytterhoeven 	sh_pfc_write(pfc, reg, pfc->saved_regs[idx]);
664077365a9SGeert Uytterhoeven }
665077365a9SGeert Uytterhoeven 
sh_pfc_walk_regs(struct sh_pfc * pfc,void (* do_reg)(struct sh_pfc * pfc,u32 reg,unsigned int idx))666077365a9SGeert Uytterhoeven static unsigned int sh_pfc_walk_regs(struct sh_pfc *pfc,
667077365a9SGeert Uytterhoeven 	void (*do_reg)(struct sh_pfc *pfc, u32 reg, unsigned int idx))
668077365a9SGeert Uytterhoeven {
669077365a9SGeert Uytterhoeven 	unsigned int i, n = 0;
670077365a9SGeert Uytterhoeven 
671077365a9SGeert Uytterhoeven 	if (pfc->info->cfg_regs)
672077365a9SGeert Uytterhoeven 		for (i = 0; pfc->info->cfg_regs[i].reg; i++)
673077365a9SGeert Uytterhoeven 			do_reg(pfc, pfc->info->cfg_regs[i].reg, n++);
674077365a9SGeert Uytterhoeven 
675077365a9SGeert Uytterhoeven 	if (pfc->info->drive_regs)
676077365a9SGeert Uytterhoeven 		for (i = 0; pfc->info->drive_regs[i].reg; i++)
677077365a9SGeert Uytterhoeven 			do_reg(pfc, pfc->info->drive_regs[i].reg, n++);
678077365a9SGeert Uytterhoeven 
679077365a9SGeert Uytterhoeven 	if (pfc->info->bias_regs)
680412da8c7SGeert Uytterhoeven 		for (i = 0; pfc->info->bias_regs[i].puen ||
681412da8c7SGeert Uytterhoeven 			    pfc->info->bias_regs[i].pud; i++) {
682412da8c7SGeert Uytterhoeven 			if (pfc->info->bias_regs[i].puen)
683077365a9SGeert Uytterhoeven 				do_reg(pfc, pfc->info->bias_regs[i].puen, n++);
684077365a9SGeert Uytterhoeven 			if (pfc->info->bias_regs[i].pud)
685077365a9SGeert Uytterhoeven 				do_reg(pfc, pfc->info->bias_regs[i].pud, n++);
686077365a9SGeert Uytterhoeven 		}
687077365a9SGeert Uytterhoeven 
688077365a9SGeert Uytterhoeven 	if (pfc->info->ioctrl_regs)
689077365a9SGeert Uytterhoeven 		for (i = 0; pfc->info->ioctrl_regs[i].reg; i++)
690077365a9SGeert Uytterhoeven 			do_reg(pfc, pfc->info->ioctrl_regs[i].reg, n++);
691077365a9SGeert Uytterhoeven 
692077365a9SGeert Uytterhoeven 	return n;
693077365a9SGeert Uytterhoeven }
694077365a9SGeert Uytterhoeven 
sh_pfc_suspend_init(struct sh_pfc * pfc)695077365a9SGeert Uytterhoeven static int sh_pfc_suspend_init(struct sh_pfc *pfc)
696077365a9SGeert Uytterhoeven {
697077365a9SGeert Uytterhoeven 	unsigned int n;
698077365a9SGeert Uytterhoeven 
699077365a9SGeert Uytterhoeven 	/* This is the best we can do to check for the presence of PSCI */
700077365a9SGeert Uytterhoeven 	if (!psci_ops.cpu_suspend)
701077365a9SGeert Uytterhoeven 		return 0;
702077365a9SGeert Uytterhoeven 
703077365a9SGeert Uytterhoeven 	n = sh_pfc_walk_regs(pfc, sh_pfc_nop_reg);
704077365a9SGeert Uytterhoeven 	if (!n)
705077365a9SGeert Uytterhoeven 		return 0;
706077365a9SGeert Uytterhoeven 
707077365a9SGeert Uytterhoeven 	pfc->saved_regs = devm_kmalloc_array(pfc->dev, n,
708077365a9SGeert Uytterhoeven 					     sizeof(*pfc->saved_regs),
709077365a9SGeert Uytterhoeven 					     GFP_KERNEL);
710077365a9SGeert Uytterhoeven 	if (!pfc->saved_regs)
711077365a9SGeert Uytterhoeven 		return -ENOMEM;
712077365a9SGeert Uytterhoeven 
713077365a9SGeert Uytterhoeven 	dev_dbg(pfc->dev, "Allocated space to save %u regs\n", n);
714077365a9SGeert Uytterhoeven 	return 0;
715077365a9SGeert Uytterhoeven }
716077365a9SGeert Uytterhoeven 
sh_pfc_suspend_noirq(struct device * dev)717077365a9SGeert Uytterhoeven static int sh_pfc_suspend_noirq(struct device *dev)
718077365a9SGeert Uytterhoeven {
719077365a9SGeert Uytterhoeven 	struct sh_pfc *pfc = dev_get_drvdata(dev);
720077365a9SGeert Uytterhoeven 
721077365a9SGeert Uytterhoeven 	if (pfc->saved_regs)
722077365a9SGeert Uytterhoeven 		sh_pfc_walk_regs(pfc, sh_pfc_save_reg);
723077365a9SGeert Uytterhoeven 	return 0;
724077365a9SGeert Uytterhoeven }
725077365a9SGeert Uytterhoeven 
sh_pfc_resume_noirq(struct device * dev)726077365a9SGeert Uytterhoeven static int sh_pfc_resume_noirq(struct device *dev)
727077365a9SGeert Uytterhoeven {
728077365a9SGeert Uytterhoeven 	struct sh_pfc *pfc = dev_get_drvdata(dev);
729077365a9SGeert Uytterhoeven 
730077365a9SGeert Uytterhoeven 	if (pfc->saved_regs)
731077365a9SGeert Uytterhoeven 		sh_pfc_walk_regs(pfc, sh_pfc_restore_reg);
732077365a9SGeert Uytterhoeven 	return 0;
733077365a9SGeert Uytterhoeven }
73493664eb8SGeert Uytterhoeven #define pm_psci_sleep_ptr(_ptr)	pm_sleep_ptr(_ptr)
735077365a9SGeert Uytterhoeven #else
sh_pfc_suspend_init(struct sh_pfc * pfc)736077365a9SGeert Uytterhoeven static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; }
sh_pfc_suspend_noirq(struct device * dev)737727eb02eSAndy Shevchenko static int sh_pfc_suspend_noirq(struct device *dev) { return 0; }
sh_pfc_resume_noirq(struct device * dev)738727eb02eSAndy Shevchenko static int sh_pfc_resume_noirq(struct device *dev) { return 0; }
73993664eb8SGeert Uytterhoeven #define pm_psci_sleep_ptr(_ptr)	PTR_IF(false, (_ptr))
740727eb02eSAndy Shevchenko #endif	/* CONFIG_ARM_PSCI_FW */
741727eb02eSAndy Shevchenko 
742727eb02eSAndy Shevchenko static DEFINE_NOIRQ_DEV_PM_OPS(sh_pfc_pm, sh_pfc_suspend_noirq, sh_pfc_resume_noirq);
743077365a9SGeert Uytterhoeven 
744077365a9SGeert Uytterhoeven #ifdef DEBUG
745077365a9SGeert Uytterhoeven #define SH_PFC_MAX_REGS		300
746de9b8610SGeert Uytterhoeven #define SH_PFC_MAX_ENUMS	5000
747077365a9SGeert Uytterhoeven 
748075667ccSJason Wang static unsigned int sh_pfc_errors __initdata;
749075667ccSJason Wang static unsigned int sh_pfc_warnings __initdata;
7504eb5a6eeSGeert Uytterhoeven static bool sh_pfc_bias_done __initdata;
751854476b8SGeert Uytterhoeven static bool sh_pfc_drive_done __initdata;
7528d1c50b8SGeert Uytterhoeven static bool sh_pfc_power_done __initdata;
753e212923eSGeert Uytterhoeven static struct {
754e212923eSGeert Uytterhoeven 	u32 reg;
755e212923eSGeert Uytterhoeven 	u32 bits;
756e212923eSGeert Uytterhoeven } *sh_pfc_regs __initdata;
757075667ccSJason Wang static u32 sh_pfc_num_regs __initdata;
758075667ccSJason Wang static u16 *sh_pfc_enums __initdata;
759075667ccSJason Wang static u32 sh_pfc_num_enums __initdata;
760077365a9SGeert Uytterhoeven 
761077365a9SGeert Uytterhoeven #define sh_pfc_err(fmt, ...)					\
762077365a9SGeert Uytterhoeven 	do {							\
763077365a9SGeert Uytterhoeven 		pr_err("%s: " fmt, drvname, ##__VA_ARGS__);	\
764077365a9SGeert Uytterhoeven 		sh_pfc_errors++;				\
765077365a9SGeert Uytterhoeven 	} while (0)
7664eb5a6eeSGeert Uytterhoeven 
7674eb5a6eeSGeert Uytterhoeven #define sh_pfc_err_once(type, fmt, ...)				\
7684eb5a6eeSGeert Uytterhoeven 	do {							\
7694eb5a6eeSGeert Uytterhoeven 		if (!sh_pfc_ ## type ## _done) {		\
7704eb5a6eeSGeert Uytterhoeven 			sh_pfc_ ## type ## _done = true;	\
7714eb5a6eeSGeert Uytterhoeven 			sh_pfc_err(fmt, ##__VA_ARGS__);		\
7724eb5a6eeSGeert Uytterhoeven 		}						\
7734eb5a6eeSGeert Uytterhoeven 	} while (0)
7744eb5a6eeSGeert Uytterhoeven 
775077365a9SGeert Uytterhoeven #define sh_pfc_warn(fmt, ...)					\
776077365a9SGeert Uytterhoeven 	do {							\
777077365a9SGeert Uytterhoeven 		pr_warn("%s: " fmt, drvname, ##__VA_ARGS__);	\
778077365a9SGeert Uytterhoeven 		sh_pfc_warnings++;				\
779077365a9SGeert Uytterhoeven 	} while (0)
780077365a9SGeert Uytterhoeven 
is0s(const u16 * enum_ids,unsigned int n)781077365a9SGeert Uytterhoeven static bool __init is0s(const u16 *enum_ids, unsigned int n)
782077365a9SGeert Uytterhoeven {
783077365a9SGeert Uytterhoeven 	unsigned int i;
784077365a9SGeert Uytterhoeven 
785077365a9SGeert Uytterhoeven 	for (i = 0; i < n; i++)
786077365a9SGeert Uytterhoeven 		if (enum_ids[i])
787077365a9SGeert Uytterhoeven 			return false;
788077365a9SGeert Uytterhoeven 
789077365a9SGeert Uytterhoeven 	return true;
790077365a9SGeert Uytterhoeven }
791077365a9SGeert Uytterhoeven 
same_name(const char * a,const char * b)792077365a9SGeert Uytterhoeven static bool __init same_name(const char *a, const char *b)
793077365a9SGeert Uytterhoeven {
79427b32fbbSGeert Uytterhoeven 	return a && b && !strcmp(a, b);
795077365a9SGeert Uytterhoeven }
796077365a9SGeert Uytterhoeven 
sh_pfc_check_reg(const char * drvname,u32 reg,u32 bits)797e212923eSGeert Uytterhoeven static void __init sh_pfc_check_reg(const char *drvname, u32 reg, u32 bits)
798077365a9SGeert Uytterhoeven {
799077365a9SGeert Uytterhoeven 	unsigned int i;
800077365a9SGeert Uytterhoeven 
801e212923eSGeert Uytterhoeven 	for (i = 0; i < sh_pfc_num_regs; i++) {
802e212923eSGeert Uytterhoeven 		if (reg != sh_pfc_regs[i].reg)
803e212923eSGeert Uytterhoeven 			continue;
804e212923eSGeert Uytterhoeven 
805e212923eSGeert Uytterhoeven 		if (bits & sh_pfc_regs[i].bits)
806e212923eSGeert Uytterhoeven 			sh_pfc_err("reg 0x%x: bits 0x%x conflict\n", reg,
807e212923eSGeert Uytterhoeven 				   bits & sh_pfc_regs[i].bits);
808e212923eSGeert Uytterhoeven 
809e212923eSGeert Uytterhoeven 		sh_pfc_regs[i].bits |= bits;
810077365a9SGeert Uytterhoeven 		return;
811077365a9SGeert Uytterhoeven 	}
812077365a9SGeert Uytterhoeven 
813077365a9SGeert Uytterhoeven 	if (sh_pfc_num_regs == SH_PFC_MAX_REGS) {
814077365a9SGeert Uytterhoeven 		pr_warn_once("%s: Please increase SH_PFC_MAX_REGS\n", drvname);
815077365a9SGeert Uytterhoeven 		return;
816077365a9SGeert Uytterhoeven 	}
817077365a9SGeert Uytterhoeven 
818e212923eSGeert Uytterhoeven 	sh_pfc_regs[sh_pfc_num_regs].reg = reg;
819e212923eSGeert Uytterhoeven 	sh_pfc_regs[sh_pfc_num_regs].bits = bits;
820e212923eSGeert Uytterhoeven 	sh_pfc_num_regs++;
821077365a9SGeert Uytterhoeven }
822077365a9SGeert Uytterhoeven 
sh_pfc_check_enum(const char * drvname,u16 enum_id)823077365a9SGeert Uytterhoeven static int __init sh_pfc_check_enum(const char *drvname, u16 enum_id)
824077365a9SGeert Uytterhoeven {
825077365a9SGeert Uytterhoeven 	unsigned int i;
826077365a9SGeert Uytterhoeven 
827077365a9SGeert Uytterhoeven 	for (i = 0; i < sh_pfc_num_enums; i++) {
828077365a9SGeert Uytterhoeven 		if (enum_id == sh_pfc_enums[i])
829077365a9SGeert Uytterhoeven 			return -EINVAL;
830077365a9SGeert Uytterhoeven 	}
831077365a9SGeert Uytterhoeven 
832077365a9SGeert Uytterhoeven 	if (sh_pfc_num_enums == SH_PFC_MAX_ENUMS) {
833077365a9SGeert Uytterhoeven 		pr_warn_once("%s: Please increase SH_PFC_MAX_ENUMS\n", drvname);
834077365a9SGeert Uytterhoeven 		return 0;
835077365a9SGeert Uytterhoeven 	}
836077365a9SGeert Uytterhoeven 
837077365a9SGeert Uytterhoeven 	sh_pfc_enums[sh_pfc_num_enums++] = enum_id;
838077365a9SGeert Uytterhoeven 	return 0;
839077365a9SGeert Uytterhoeven }
840077365a9SGeert Uytterhoeven 
sh_pfc_check_reg_enums(const char * drvname,u32 reg,const u16 * enums,unsigned int n)841077365a9SGeert Uytterhoeven static void __init sh_pfc_check_reg_enums(const char *drvname, u32 reg,
842077365a9SGeert Uytterhoeven 					  const u16 *enums, unsigned int n)
843077365a9SGeert Uytterhoeven {
844077365a9SGeert Uytterhoeven 	unsigned int i;
845077365a9SGeert Uytterhoeven 
846077365a9SGeert Uytterhoeven 	for (i = 0; i < n; i++) {
847077365a9SGeert Uytterhoeven 		if (enums[i] && sh_pfc_check_enum(drvname, enums[i]))
848077365a9SGeert Uytterhoeven 			sh_pfc_err("reg 0x%x enum_id %u conflict\n", reg,
849077365a9SGeert Uytterhoeven 				   enums[i]);
850077365a9SGeert Uytterhoeven 	}
851077365a9SGeert Uytterhoeven }
852077365a9SGeert Uytterhoeven 
sh_pfc_find_pin(const struct sh_pfc_soc_info * info,u32 reg,unsigned int pin)8534eb5a6eeSGeert Uytterhoeven static const struct sh_pfc_pin __init *sh_pfc_find_pin(
8544eb5a6eeSGeert Uytterhoeven 	const struct sh_pfc_soc_info *info, u32 reg, unsigned int pin)
855077365a9SGeert Uytterhoeven {
856077365a9SGeert Uytterhoeven 	const char *drvname = info->name;
857077365a9SGeert Uytterhoeven 	unsigned int i;
858077365a9SGeert Uytterhoeven 
859077365a9SGeert Uytterhoeven 	if (pin == SH_PFC_PIN_NONE)
8604eb5a6eeSGeert Uytterhoeven 		return NULL;
861077365a9SGeert Uytterhoeven 
862077365a9SGeert Uytterhoeven 	for (i = 0; i < info->nr_pins; i++) {
863077365a9SGeert Uytterhoeven 		if (pin == info->pins[i].pin)
8644eb5a6eeSGeert Uytterhoeven 			return &info->pins[i];
865077365a9SGeert Uytterhoeven 	}
866077365a9SGeert Uytterhoeven 
867077365a9SGeert Uytterhoeven 	sh_pfc_err("reg 0x%x: pin %u not found\n", reg, pin);
8684eb5a6eeSGeert Uytterhoeven 	return NULL;
869077365a9SGeert Uytterhoeven }
870077365a9SGeert Uytterhoeven 
sh_pfc_check_cfg_reg(const char * drvname,const struct pinmux_cfg_reg * cfg_reg)871077365a9SGeert Uytterhoeven static void __init sh_pfc_check_cfg_reg(const char *drvname,
872077365a9SGeert Uytterhoeven 					const struct pinmux_cfg_reg *cfg_reg)
873077365a9SGeert Uytterhoeven {
874fc883ed5SGeert Uytterhoeven 	unsigned int i, n, rw, r;
87562109055SGeert Uytterhoeven 	int fw;
876077365a9SGeert Uytterhoeven 
877e212923eSGeert Uytterhoeven 	sh_pfc_check_reg(drvname, cfg_reg->reg,
878e212923eSGeert Uytterhoeven 			 GENMASK(cfg_reg->reg_width - 1, 0));
879077365a9SGeert Uytterhoeven 
880077365a9SGeert Uytterhoeven 	if (cfg_reg->field_width) {
881de9b8610SGeert Uytterhoeven 		fw = cfg_reg->field_width;
882de9b8610SGeert Uytterhoeven 		n = (cfg_reg->reg_width / fw) << fw;
883fc883ed5SGeert Uytterhoeven 		for (i = 0, r = 0; i < n; i += 1 << fw) {
884fc883ed5SGeert Uytterhoeven 			if (is0s(&cfg_reg->enum_ids[i], 1 << fw))
885fc883ed5SGeert Uytterhoeven 				r++;
886fc883ed5SGeert Uytterhoeven 		}
887fc883ed5SGeert Uytterhoeven 
888fc883ed5SGeert Uytterhoeven 		if ((r << fw) * sizeof(u16) > cfg_reg->reg_width / fw)
889fc883ed5SGeert Uytterhoeven 			sh_pfc_warn("reg 0x%x can be described with variable-width reserved fields\n",
890fc883ed5SGeert Uytterhoeven 				    cfg_reg->reg);
891fc883ed5SGeert Uytterhoeven 
892077365a9SGeert Uytterhoeven 		/* Skip field checks (done at build time) */
893077365a9SGeert Uytterhoeven 		goto check_enum_ids;
894077365a9SGeert Uytterhoeven 	}
895077365a9SGeert Uytterhoeven 
896077365a9SGeert Uytterhoeven 	for (i = 0, n = 0, rw = 0; (fw = cfg_reg->var_field_width[i]); i++) {
89762109055SGeert Uytterhoeven 		if (fw < 0) {
89862109055SGeert Uytterhoeven 			rw += -fw;
89962109055SGeert Uytterhoeven 		} else {
90062109055SGeert Uytterhoeven 			if (is0s(&cfg_reg->enum_ids[n], 1 << fw))
90162109055SGeert Uytterhoeven 				sh_pfc_warn("reg 0x%x: field [%u:%u] can be described as reserved\n",
902077365a9SGeert Uytterhoeven 					    cfg_reg->reg, rw, rw + fw - 1);
903077365a9SGeert Uytterhoeven 			n += 1 << fw;
904077365a9SGeert Uytterhoeven 			rw += fw;
905077365a9SGeert Uytterhoeven 		}
90662109055SGeert Uytterhoeven 	}
907077365a9SGeert Uytterhoeven 
908077365a9SGeert Uytterhoeven 	if (rw != cfg_reg->reg_width)
909077365a9SGeert Uytterhoeven 		sh_pfc_err("reg 0x%x: var_field_width declares %u instead of %u bits\n",
910077365a9SGeert Uytterhoeven 			   cfg_reg->reg, rw, cfg_reg->reg_width);
911077365a9SGeert Uytterhoeven 
912*56f5e36dSGeert Uytterhoeven 	if (n != cfg_reg->nr_enum_ids) {
913077365a9SGeert Uytterhoeven 		sh_pfc_err("reg 0x%x: enum_ids[] has %u instead of %u values\n",
914077365a9SGeert Uytterhoeven 			   cfg_reg->reg, cfg_reg->nr_enum_ids, n);
915*56f5e36dSGeert Uytterhoeven 		n = cfg_reg->nr_enum_ids;
916*56f5e36dSGeert Uytterhoeven 	}
917077365a9SGeert Uytterhoeven 
918077365a9SGeert Uytterhoeven check_enum_ids:
919077365a9SGeert Uytterhoeven 	sh_pfc_check_reg_enums(drvname, cfg_reg->reg, cfg_reg->enum_ids, n);
920077365a9SGeert Uytterhoeven }
921077365a9SGeert Uytterhoeven 
sh_pfc_check_drive_reg(const struct sh_pfc_soc_info * info,const struct pinmux_drive_reg * drive)922077365a9SGeert Uytterhoeven static void __init sh_pfc_check_drive_reg(const struct sh_pfc_soc_info *info,
923077365a9SGeert Uytterhoeven 					  const struct pinmux_drive_reg *drive)
924077365a9SGeert Uytterhoeven {
925854476b8SGeert Uytterhoeven 	const char *drvname = info->name;
926854476b8SGeert Uytterhoeven 	const struct sh_pfc_pin *pin;
927077365a9SGeert Uytterhoeven 	unsigned int i;
928077365a9SGeert Uytterhoeven 
929077365a9SGeert Uytterhoeven 	for (i = 0; i < ARRAY_SIZE(drive->fields); i++) {
930077365a9SGeert Uytterhoeven 		const struct pinmux_drive_reg_field *field = &drive->fields[i];
931077365a9SGeert Uytterhoeven 
932077365a9SGeert Uytterhoeven 		if (!field->pin && !field->offset && !field->size)
933077365a9SGeert Uytterhoeven 			continue;
934077365a9SGeert Uytterhoeven 
935e212923eSGeert Uytterhoeven 		sh_pfc_check_reg(info->name, drive->reg,
936e212923eSGeert Uytterhoeven 				 GENMASK(field->offset + field->size - 1,
937e212923eSGeert Uytterhoeven 					 field->offset));
938077365a9SGeert Uytterhoeven 
939854476b8SGeert Uytterhoeven 		pin = sh_pfc_find_pin(info, drive->reg, field->pin);
940854476b8SGeert Uytterhoeven 		if (pin && !(pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH))
941854476b8SGeert Uytterhoeven 			sh_pfc_err("drive_reg 0x%x: field %u: pin %s lacks SH_PFC_PIN_CFG_DRIVE_STRENGTH flag\n",
942854476b8SGeert Uytterhoeven 				   drive->reg, i, pin->name);
943077365a9SGeert Uytterhoeven 	}
944077365a9SGeert Uytterhoeven }
945077365a9SGeert Uytterhoeven 
sh_pfc_check_bias_reg(const struct sh_pfc_soc_info * info,const struct pinmux_bias_reg * bias)946077365a9SGeert Uytterhoeven static void __init sh_pfc_check_bias_reg(const struct sh_pfc_soc_info *info,
947077365a9SGeert Uytterhoeven 					 const struct pinmux_bias_reg *bias)
948077365a9SGeert Uytterhoeven {
9494eb5a6eeSGeert Uytterhoeven 	const char *drvname = info->name;
9504eb5a6eeSGeert Uytterhoeven 	const struct sh_pfc_pin *pin;
951077365a9SGeert Uytterhoeven 	unsigned int i;
952e212923eSGeert Uytterhoeven 	u32 bits;
953077365a9SGeert Uytterhoeven 
954e212923eSGeert Uytterhoeven 	for (i = 0, bits = 0; i < ARRAY_SIZE(bias->pins); i++)
955e212923eSGeert Uytterhoeven 		if (bias->pins[i] != SH_PFC_PIN_NONE)
956e212923eSGeert Uytterhoeven 			bits |= BIT(i);
957e212923eSGeert Uytterhoeven 
958f31a5ffbSGeert Uytterhoeven 	if (bias->puen)
959e212923eSGeert Uytterhoeven 		sh_pfc_check_reg(info->name, bias->puen, bits);
960077365a9SGeert Uytterhoeven 	if (bias->pud)
961e212923eSGeert Uytterhoeven 		sh_pfc_check_reg(info->name, bias->pud, bits);
9624eb5a6eeSGeert Uytterhoeven 	for (i = 0; i < ARRAY_SIZE(bias->pins); i++) {
9634eb5a6eeSGeert Uytterhoeven 		pin = sh_pfc_find_pin(info, bias->puen, bias->pins[i]);
9644eb5a6eeSGeert Uytterhoeven 		if (!pin)
9654eb5a6eeSGeert Uytterhoeven 			continue;
9664eb5a6eeSGeert Uytterhoeven 
9674eb5a6eeSGeert Uytterhoeven 		if (bias->puen && bias->pud) {
9684eb5a6eeSGeert Uytterhoeven 			/*
9694eb5a6eeSGeert Uytterhoeven 			 * Pull-enable and pull-up/down control registers
9704eb5a6eeSGeert Uytterhoeven 			 * As some SoCs have pins that support only pull-up
9714eb5a6eeSGeert Uytterhoeven 			 * or pull-down, we just check for one of them
9724eb5a6eeSGeert Uytterhoeven 			 */
9734eb5a6eeSGeert Uytterhoeven 			if (!(pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN))
9744eb5a6eeSGeert Uytterhoeven 				sh_pfc_err("bias_reg 0x%x:%u: pin %s lacks one or more SH_PFC_PIN_CFG_PULL_* flags\n",
9754eb5a6eeSGeert Uytterhoeven 					   bias->puen, i, pin->name);
9764eb5a6eeSGeert Uytterhoeven 		} else if (bias->puen) {
9774eb5a6eeSGeert Uytterhoeven 			/* Pull-up control register only */
9784eb5a6eeSGeert Uytterhoeven 			if (!(pin->configs & SH_PFC_PIN_CFG_PULL_UP))
9794eb5a6eeSGeert Uytterhoeven 				sh_pfc_err("bias_reg 0x%x:%u: pin %s lacks SH_PFC_PIN_CFG_PULL_UP flag\n",
9804eb5a6eeSGeert Uytterhoeven 					   bias->puen, i, pin->name);
9814eb5a6eeSGeert Uytterhoeven 		} else if (bias->pud) {
9824eb5a6eeSGeert Uytterhoeven 			/* Pull-down control register only */
9834eb5a6eeSGeert Uytterhoeven 			if (!(pin->configs & SH_PFC_PIN_CFG_PULL_DOWN))
9844eb5a6eeSGeert Uytterhoeven 				sh_pfc_err("bias_reg 0x%x:%u: pin %s lacks SH_PFC_PIN_CFG_PULL_DOWN flag\n",
9854eb5a6eeSGeert Uytterhoeven 					   bias->pud, i, pin->name);
9864eb5a6eeSGeert Uytterhoeven 		}
9874eb5a6eeSGeert Uytterhoeven 	}
988077365a9SGeert Uytterhoeven }
989077365a9SGeert Uytterhoeven 
sh_pfc_compare_groups(const char * drvname,const struct sh_pfc_pin_group * a,const struct sh_pfc_pin_group * b)9904bb9514cSGeert Uytterhoeven static void __init sh_pfc_compare_groups(const char *drvname,
9914bb9514cSGeert Uytterhoeven 					 const struct sh_pfc_pin_group *a,
9924bb9514cSGeert Uytterhoeven 					 const struct sh_pfc_pin_group *b)
9934bb9514cSGeert Uytterhoeven {
9944bb9514cSGeert Uytterhoeven 	unsigned int i;
9954bb9514cSGeert Uytterhoeven 	size_t len;
9964bb9514cSGeert Uytterhoeven 
9974bb9514cSGeert Uytterhoeven 	if (same_name(a->name, b->name))
9984bb9514cSGeert Uytterhoeven 		sh_pfc_err("group %s: name conflict\n", a->name);
9994bb9514cSGeert Uytterhoeven 
10004bb9514cSGeert Uytterhoeven 	if (a->nr_pins > b->nr_pins)
10014bb9514cSGeert Uytterhoeven 		swap(a, b);
10024bb9514cSGeert Uytterhoeven 
10034bb9514cSGeert Uytterhoeven 	len = a->nr_pins * sizeof(a->pins[0]);
10044bb9514cSGeert Uytterhoeven 	for (i = 0; i <= b->nr_pins - a->nr_pins; i++) {
10054bb9514cSGeert Uytterhoeven 		if (a->pins == b->pins + i || a->mux == b->mux + i ||
10064bb9514cSGeert Uytterhoeven 		    memcmp(a->pins, b->pins + i, len) ||
10074bb9514cSGeert Uytterhoeven 		    memcmp(a->mux, b->mux + i, len))
10084bb9514cSGeert Uytterhoeven 			continue;
10094bb9514cSGeert Uytterhoeven 
10104bb9514cSGeert Uytterhoeven 		if (a->nr_pins == b->nr_pins)
10114bb9514cSGeert Uytterhoeven 			sh_pfc_warn("group %s can be an alias for %s\n",
10124bb9514cSGeert Uytterhoeven 				    a->name, b->name);
10134bb9514cSGeert Uytterhoeven 		else
10144bb9514cSGeert Uytterhoeven 			sh_pfc_warn("group %s is a subset of %s\n", a->name,
10154bb9514cSGeert Uytterhoeven 				    b->name);
10164bb9514cSGeert Uytterhoeven 	}
10174bb9514cSGeert Uytterhoeven }
10184bb9514cSGeert Uytterhoeven 
sh_pfc_check_info(const struct sh_pfc_soc_info * info)1019077365a9SGeert Uytterhoeven static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info)
1020077365a9SGeert Uytterhoeven {
1021854476b8SGeert Uytterhoeven 	const struct pinmux_drive_reg *drive_regs = info->drive_regs;
1022dd035683SGeert Uytterhoeven #define drive_nfields	ARRAY_SIZE(drive_regs->fields)
1023dd035683SGeert Uytterhoeven #define drive_ofs(i)	drive_regs[(i) / drive_nfields]
1024dd035683SGeert Uytterhoeven #define drive_reg(i)	drive_ofs(i).reg
1025dd035683SGeert Uytterhoeven #define drive_bit(i)	((i) % drive_nfields)
1026dd035683SGeert Uytterhoeven #define drive_field(i)	drive_ofs(i).fields[drive_bit(i)]
1027f31a5ffbSGeert Uytterhoeven 	const struct pinmux_bias_reg *bias_regs = info->bias_regs;
1028dd035683SGeert Uytterhoeven #define bias_npins	ARRAY_SIZE(bias_regs->pins)
1029dd035683SGeert Uytterhoeven #define bias_ofs(i)	bias_regs[(i) / bias_npins]
1030dd035683SGeert Uytterhoeven #define bias_puen(i)	bias_ofs(i).puen
1031dd035683SGeert Uytterhoeven #define bias_pud(i)	bias_ofs(i).pud
1032dd035683SGeert Uytterhoeven #define bias_bit(i)	((i) % bias_npins)
1033dd035683SGeert Uytterhoeven #define bias_pin(i)	bias_ofs(i).pins[bias_bit(i)]
1034077365a9SGeert Uytterhoeven 	const char *drvname = info->name;
1035077365a9SGeert Uytterhoeven 	unsigned int *refcnts;
1036077365a9SGeert Uytterhoeven 	unsigned int i, j, k;
1037077365a9SGeert Uytterhoeven 
1038f4e260bfSGeert Uytterhoeven 	pr_info("sh_pfc: Checking %s\n", drvname);
1039077365a9SGeert Uytterhoeven 	sh_pfc_num_regs = 0;
1040077365a9SGeert Uytterhoeven 	sh_pfc_num_enums = 0;
10414eb5a6eeSGeert Uytterhoeven 	sh_pfc_bias_done = false;
1042854476b8SGeert Uytterhoeven 	sh_pfc_drive_done = false;
10438d1c50b8SGeert Uytterhoeven 	sh_pfc_power_done = false;
1044077365a9SGeert Uytterhoeven 
1045077365a9SGeert Uytterhoeven 	/* Check pins */
1046077365a9SGeert Uytterhoeven 	for (i = 0; i < info->nr_pins; i++) {
1047077365a9SGeert Uytterhoeven 		const struct sh_pfc_pin *pin = &info->pins[i];
10484eb5a6eeSGeert Uytterhoeven 		unsigned int x;
1049077365a9SGeert Uytterhoeven 
1050077365a9SGeert Uytterhoeven 		if (!pin->name) {
1051077365a9SGeert Uytterhoeven 			sh_pfc_err("empty pin %u\n", i);
1052077365a9SGeert Uytterhoeven 			continue;
1053077365a9SGeert Uytterhoeven 		}
1054077365a9SGeert Uytterhoeven 		for (j = 0; j < i; j++) {
1055077365a9SGeert Uytterhoeven 			const struct sh_pfc_pin *pin2 = &info->pins[j];
1056077365a9SGeert Uytterhoeven 
1057077365a9SGeert Uytterhoeven 			if (same_name(pin->name, pin2->name))
1058077365a9SGeert Uytterhoeven 				sh_pfc_err("pin %s: name conflict\n",
1059077365a9SGeert Uytterhoeven 					   pin->name);
1060077365a9SGeert Uytterhoeven 
1061077365a9SGeert Uytterhoeven 			if (pin->pin != (u16)-1 && pin->pin == pin2->pin)
1062077365a9SGeert Uytterhoeven 				sh_pfc_err("pin %s/%s: pin %u conflict\n",
1063077365a9SGeert Uytterhoeven 					   pin->name, pin2->name, pin->pin);
1064077365a9SGeert Uytterhoeven 
1065077365a9SGeert Uytterhoeven 			if (pin->enum_id && pin->enum_id == pin2->enum_id)
1066077365a9SGeert Uytterhoeven 				sh_pfc_err("pin %s/%s: enum_id %u conflict\n",
1067077365a9SGeert Uytterhoeven 					   pin->name, pin2->name,
1068077365a9SGeert Uytterhoeven 					   pin->enum_id);
1069077365a9SGeert Uytterhoeven 		}
10704eb5a6eeSGeert Uytterhoeven 
10714eb5a6eeSGeert Uytterhoeven 		if (pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN) {
10724eb5a6eeSGeert Uytterhoeven 			if (!info->ops || !info->ops->get_bias ||
10734eb5a6eeSGeert Uytterhoeven 			    !info->ops->set_bias)
10744eb5a6eeSGeert Uytterhoeven 				sh_pfc_err_once(bias, "SH_PFC_PIN_CFG_PULL_* flag set but .[gs]et_bias() not implemented\n");
10754eb5a6eeSGeert Uytterhoeven 
10764eb5a6eeSGeert Uytterhoeven 			if (!bias_regs &&
10774eb5a6eeSGeert Uytterhoeven 			     (!info->ops || !info->ops->pin_to_portcr))
10784eb5a6eeSGeert Uytterhoeven 				sh_pfc_err_once(bias, "SH_PFC_PIN_CFG_PULL_UP flag set but no bias_regs defined and .pin_to_portcr() not implemented\n");
10794eb5a6eeSGeert Uytterhoeven 		}
10804eb5a6eeSGeert Uytterhoeven 
10814eb5a6eeSGeert Uytterhoeven 		if ((pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN) && bias_regs) {
10824eb5a6eeSGeert Uytterhoeven 			const struct pinmux_bias_reg *bias_reg =
10834eb5a6eeSGeert Uytterhoeven 				rcar_pin_to_bias_reg(info, pin->pin, &x);
10844eb5a6eeSGeert Uytterhoeven 
10854eb5a6eeSGeert Uytterhoeven 			if (!bias_reg ||
10864eb5a6eeSGeert Uytterhoeven 			    ((pin->configs & SH_PFC_PIN_CFG_PULL_UP) &&
10874eb5a6eeSGeert Uytterhoeven 			     !bias_reg->puen))
10884eb5a6eeSGeert Uytterhoeven 				sh_pfc_err("pin %s: SH_PFC_PIN_CFG_PULL_UP flag set but pin not in bias_regs\n",
10894eb5a6eeSGeert Uytterhoeven 					   pin->name);
10904eb5a6eeSGeert Uytterhoeven 
10914eb5a6eeSGeert Uytterhoeven 			if (!bias_reg ||
10924eb5a6eeSGeert Uytterhoeven 			    ((pin->configs & SH_PFC_PIN_CFG_PULL_DOWN) &&
10934eb5a6eeSGeert Uytterhoeven 			     !bias_reg->pud))
10944eb5a6eeSGeert Uytterhoeven 				sh_pfc_err("pin %s: SH_PFC_PIN_CFG_PULL_DOWN flag set but pin not in bias_regs\n",
10954eb5a6eeSGeert Uytterhoeven 					   pin->name);
10964eb5a6eeSGeert Uytterhoeven 		}
1097854476b8SGeert Uytterhoeven 
1098854476b8SGeert Uytterhoeven 		if (pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH) {
1099854476b8SGeert Uytterhoeven 			if (!drive_regs) {
1100854476b8SGeert Uytterhoeven 				sh_pfc_err_once(drive, "SH_PFC_PIN_CFG_DRIVE_STRENGTH flag set but drive_regs missing\n");
1101854476b8SGeert Uytterhoeven 			} else {
1102dd035683SGeert Uytterhoeven 				for (j = 0; drive_reg(j); j++) {
1103dd035683SGeert Uytterhoeven 					if (!drive_field(j).pin &&
1104dd035683SGeert Uytterhoeven 					    !drive_field(j).offset &&
1105dd035683SGeert Uytterhoeven 					    !drive_field(j).size)
1106854476b8SGeert Uytterhoeven 						continue;
1107854476b8SGeert Uytterhoeven 
1108dd035683SGeert Uytterhoeven 					if (drive_field(j).pin == pin->pin)
1109854476b8SGeert Uytterhoeven 						break;
1110854476b8SGeert Uytterhoeven 				}
1111854476b8SGeert Uytterhoeven 
1112dd035683SGeert Uytterhoeven 				if (!drive_reg(j))
1113854476b8SGeert Uytterhoeven 					sh_pfc_err("pin %s: SH_PFC_PIN_CFG_DRIVE_STRENGTH flag set but not in drive_regs\n",
1114854476b8SGeert Uytterhoeven 						   pin->name);
1115854476b8SGeert Uytterhoeven 			}
1116854476b8SGeert Uytterhoeven 		}
11178d1c50b8SGeert Uytterhoeven 
1118b88e733aSGeert Uytterhoeven 		if (pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE_MASK) {
11198d1c50b8SGeert Uytterhoeven 			if (!info->ops || !info->ops->pin_to_pocctrl)
1120b88e733aSGeert Uytterhoeven 				sh_pfc_err_once(power, "SH_PFC_PIN_CFG_IO_VOLTAGE set but .pin_to_pocctrl() not implemented\n");
11218d1c50b8SGeert Uytterhoeven 			else if (info->ops->pin_to_pocctrl(pin->pin, &x) < 0)
11228d1c50b8SGeert Uytterhoeven 				sh_pfc_err("pin %s: SH_PFC_PIN_CFG_IO_VOLTAGE set but invalid pin_to_pocctrl()\n",
11238d1c50b8SGeert Uytterhoeven 					   pin->name);
11248d1c50b8SGeert Uytterhoeven 		} else if (info->ops && info->ops->pin_to_pocctrl &&
11258d1c50b8SGeert Uytterhoeven 			   info->ops->pin_to_pocctrl(pin->pin, &x) >= 0) {
11268d1c50b8SGeert Uytterhoeven 			sh_pfc_warn("pin %s: SH_PFC_PIN_CFG_IO_VOLTAGE not set but valid pin_to_pocctrl()\n",
11278d1c50b8SGeert Uytterhoeven 				    pin->name);
11288d1c50b8SGeert Uytterhoeven 		}
1129077365a9SGeert Uytterhoeven 	}
1130077365a9SGeert Uytterhoeven 
1131077365a9SGeert Uytterhoeven 	/* Check groups and functions */
1132077365a9SGeert Uytterhoeven 	refcnts = kcalloc(info->nr_groups, sizeof(*refcnts), GFP_KERNEL);
1133077365a9SGeert Uytterhoeven 	if (!refcnts)
1134077365a9SGeert Uytterhoeven 		return;
1135077365a9SGeert Uytterhoeven 
1136077365a9SGeert Uytterhoeven 	for (i = 0; i < info->nr_functions; i++) {
1137077365a9SGeert Uytterhoeven 		const struct sh_pfc_function *func = &info->functions[i];
1138077365a9SGeert Uytterhoeven 
1139077365a9SGeert Uytterhoeven 		if (!func->name) {
1140077365a9SGeert Uytterhoeven 			sh_pfc_err("empty function %u\n", i);
1141077365a9SGeert Uytterhoeven 			continue;
1142077365a9SGeert Uytterhoeven 		}
1143077365a9SGeert Uytterhoeven 		for (j = 0; j < i; j++) {
1144077365a9SGeert Uytterhoeven 			if (same_name(func->name, info->functions[j].name))
1145077365a9SGeert Uytterhoeven 				sh_pfc_err("function %s: name conflict\n",
1146077365a9SGeert Uytterhoeven 					   func->name);
1147077365a9SGeert Uytterhoeven 		}
1148077365a9SGeert Uytterhoeven 		for (j = 0; j < func->nr_groups; j++) {
1149077365a9SGeert Uytterhoeven 			for (k = 0; k < info->nr_groups; k++) {
1150077365a9SGeert Uytterhoeven 				if (same_name(func->groups[j],
1151077365a9SGeert Uytterhoeven 					      info->groups[k].name)) {
1152077365a9SGeert Uytterhoeven 					refcnts[k]++;
1153077365a9SGeert Uytterhoeven 					break;
1154077365a9SGeert Uytterhoeven 				}
1155077365a9SGeert Uytterhoeven 			}
1156077365a9SGeert Uytterhoeven 
1157077365a9SGeert Uytterhoeven 			if (k == info->nr_groups)
1158077365a9SGeert Uytterhoeven 				sh_pfc_err("function %s: group %s not found\n",
1159077365a9SGeert Uytterhoeven 					   func->name, func->groups[j]);
1160077365a9SGeert Uytterhoeven 		}
1161077365a9SGeert Uytterhoeven 	}
1162077365a9SGeert Uytterhoeven 
1163077365a9SGeert Uytterhoeven 	for (i = 0; i < info->nr_groups; i++) {
1164077365a9SGeert Uytterhoeven 		const struct sh_pfc_pin_group *group = &info->groups[i];
1165077365a9SGeert Uytterhoeven 
1166077365a9SGeert Uytterhoeven 		if (!group->name) {
1167077365a9SGeert Uytterhoeven 			sh_pfc_err("empty group %u\n", i);
1168077365a9SGeert Uytterhoeven 			continue;
1169077365a9SGeert Uytterhoeven 		}
11704bb9514cSGeert Uytterhoeven 		for (j = 0; j < i; j++)
11714bb9514cSGeert Uytterhoeven 			sh_pfc_compare_groups(drvname, group, &info->groups[j]);
11724bb9514cSGeert Uytterhoeven 
1173077365a9SGeert Uytterhoeven 		if (!refcnts[i])
1174077365a9SGeert Uytterhoeven 			sh_pfc_err("orphan group %s\n", group->name);
1175077365a9SGeert Uytterhoeven 		else if (refcnts[i] > 1)
1176077365a9SGeert Uytterhoeven 			sh_pfc_warn("group %s referenced by %u functions\n",
1177077365a9SGeert Uytterhoeven 				    group->name, refcnts[i]);
1178077365a9SGeert Uytterhoeven 	}
1179077365a9SGeert Uytterhoeven 
1180077365a9SGeert Uytterhoeven 	kfree(refcnts);
1181077365a9SGeert Uytterhoeven 
1182077365a9SGeert Uytterhoeven 	/* Check config register descriptions */
1183077365a9SGeert Uytterhoeven 	for (i = 0; info->cfg_regs && info->cfg_regs[i].reg; i++)
1184077365a9SGeert Uytterhoeven 		sh_pfc_check_cfg_reg(drvname, &info->cfg_regs[i]);
1185077365a9SGeert Uytterhoeven 
1186077365a9SGeert Uytterhoeven 	/* Check drive strength registers */
11874704797eSGeert Uytterhoeven 	for (i = 0; drive_regs && drive_regs[i].reg; i++)
11884704797eSGeert Uytterhoeven 		sh_pfc_check_drive_reg(info, &drive_regs[i]);
11894704797eSGeert Uytterhoeven 
1190dd035683SGeert Uytterhoeven 	for (i = 0; drive_regs && drive_reg(i); i++) {
1191dd035683SGeert Uytterhoeven 		if (!drive_field(i).pin && !drive_field(i).offset &&
1192dd035683SGeert Uytterhoeven 		    !drive_field(i).size)
11934704797eSGeert Uytterhoeven 			continue;
11944704797eSGeert Uytterhoeven 
11954704797eSGeert Uytterhoeven 		for (j = 0; j < i; j++) {
1196dd035683SGeert Uytterhoeven 			if (drive_field(i).pin == drive_field(j).pin &&
1197dd035683SGeert Uytterhoeven 			    drive_field(j).offset && drive_field(j).size) {
1198dd035683SGeert Uytterhoeven 				sh_pfc_err("drive_reg 0x%x:%zu/0x%x:%zu: pin conflict\n",
1199dd035683SGeert Uytterhoeven 					   drive_reg(i), drive_bit(i),
1200dd035683SGeert Uytterhoeven 					   drive_reg(j), drive_bit(j));
12014704797eSGeert Uytterhoeven 			}
12024704797eSGeert Uytterhoeven 		}
12034704797eSGeert Uytterhoeven 	}
1204077365a9SGeert Uytterhoeven 
1205077365a9SGeert Uytterhoeven 	/* Check bias registers */
1206f31a5ffbSGeert Uytterhoeven 	for (i = 0; bias_regs && (bias_regs[i].puen || bias_regs[i].pud); i++)
1207f31a5ffbSGeert Uytterhoeven 		sh_pfc_check_bias_reg(info, &bias_regs[i]);
1208077365a9SGeert Uytterhoeven 
1209dd035683SGeert Uytterhoeven 	for (i = 0; bias_regs && (bias_puen(i) || bias_pud(i)); i++) {
1210dd035683SGeert Uytterhoeven 		if (bias_pin(i) == SH_PFC_PIN_NONE)
12116bfbaec7SGeert Uytterhoeven 			continue;
12126bfbaec7SGeert Uytterhoeven 
12136bfbaec7SGeert Uytterhoeven 		for (j = 0; j < i; j++) {
1214dd035683SGeert Uytterhoeven 			if (bias_pin(i) != bias_pin(j))
12156bfbaec7SGeert Uytterhoeven 				continue;
12166bfbaec7SGeert Uytterhoeven 
1217dd035683SGeert Uytterhoeven 			if (bias_puen(i) && bias_puen(j))
1218dd035683SGeert Uytterhoeven 				sh_pfc_err("bias_reg 0x%x:%zu/0x%x:%zu: pin conflict\n",
1219dd035683SGeert Uytterhoeven 					   bias_puen(i), bias_bit(i),
1220dd035683SGeert Uytterhoeven 					   bias_puen(j), bias_bit(j));
1221dd035683SGeert Uytterhoeven 			if (bias_pud(i) && bias_pud(j))
1222dd035683SGeert Uytterhoeven 				sh_pfc_err("bias_reg 0x%x:%zu/0x%x:%zu: pin conflict\n",
1223dd035683SGeert Uytterhoeven 					   bias_pud(i), bias_bit(i),
1224dd035683SGeert Uytterhoeven 					   bias_pud(j), bias_bit(j));
12256bfbaec7SGeert Uytterhoeven 		}
12266bfbaec7SGeert Uytterhoeven 	}
12276bfbaec7SGeert Uytterhoeven 
1228077365a9SGeert Uytterhoeven 	/* Check ioctrl registers */
1229077365a9SGeert Uytterhoeven 	for (i = 0; info->ioctrl_regs && info->ioctrl_regs[i].reg; i++)
1230e212923eSGeert Uytterhoeven 		sh_pfc_check_reg(drvname, info->ioctrl_regs[i].reg, U32_MAX);
1231077365a9SGeert Uytterhoeven 
1232077365a9SGeert Uytterhoeven 	/* Check data registers */
1233077365a9SGeert Uytterhoeven 	for (i = 0; info->data_regs && info->data_regs[i].reg; i++) {
1234e212923eSGeert Uytterhoeven 		sh_pfc_check_reg(drvname, info->data_regs[i].reg,
1235e212923eSGeert Uytterhoeven 				 GENMASK(info->data_regs[i].reg_width - 1, 0));
1236077365a9SGeert Uytterhoeven 		sh_pfc_check_reg_enums(drvname, info->data_regs[i].reg,
1237077365a9SGeert Uytterhoeven 				       info->data_regs[i].enum_ids,
1238077365a9SGeert Uytterhoeven 				       info->data_regs[i].reg_width);
1239077365a9SGeert Uytterhoeven 	}
1240077365a9SGeert Uytterhoeven 
1241077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_SH_FUNC_GPIO
1242077365a9SGeert Uytterhoeven 	/* Check function GPIOs */
1243077365a9SGeert Uytterhoeven 	for (i = 0; i < info->nr_func_gpios; i++) {
1244077365a9SGeert Uytterhoeven 		const struct pinmux_func *func = &info->func_gpios[i];
1245077365a9SGeert Uytterhoeven 
1246077365a9SGeert Uytterhoeven 		if (!func->name) {
1247077365a9SGeert Uytterhoeven 			sh_pfc_err("empty function gpio %u\n", i);
1248077365a9SGeert Uytterhoeven 			continue;
1249077365a9SGeert Uytterhoeven 		}
1250077365a9SGeert Uytterhoeven 		for (j = 0; j < i; j++) {
1251077365a9SGeert Uytterhoeven 			if (same_name(func->name, info->func_gpios[j].name))
1252077365a9SGeert Uytterhoeven 				sh_pfc_err("func_gpio %s: name conflict\n",
1253077365a9SGeert Uytterhoeven 					   func->name);
1254077365a9SGeert Uytterhoeven 		}
1255077365a9SGeert Uytterhoeven 		if (sh_pfc_check_enum(drvname, func->enum_id))
1256077365a9SGeert Uytterhoeven 			sh_pfc_err("%s enum_id %u conflict\n", func->name,
1257077365a9SGeert Uytterhoeven 				   func->enum_id);
1258077365a9SGeert Uytterhoeven 	}
1259077365a9SGeert Uytterhoeven #endif
1260077365a9SGeert Uytterhoeven }
1261077365a9SGeert Uytterhoeven 
sh_pfc_check_driver(const struct platform_driver * pdrv)1262077365a9SGeert Uytterhoeven static void __init sh_pfc_check_driver(const struct platform_driver *pdrv)
1263077365a9SGeert Uytterhoeven {
1264077365a9SGeert Uytterhoeven 	unsigned int i;
1265077365a9SGeert Uytterhoeven 
12666dd169fcSGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_SUPERH) &&
12676dd169fcSGeert Uytterhoeven 	    !of_find_matching_node(NULL, pdrv->driver.of_match_table))
12686dd169fcSGeert Uytterhoeven 		return;
12696dd169fcSGeert Uytterhoeven 
1270077365a9SGeert Uytterhoeven 	sh_pfc_regs = kcalloc(SH_PFC_MAX_REGS, sizeof(*sh_pfc_regs),
1271077365a9SGeert Uytterhoeven 			      GFP_KERNEL);
1272077365a9SGeert Uytterhoeven 	if (!sh_pfc_regs)
1273077365a9SGeert Uytterhoeven 		return;
1274077365a9SGeert Uytterhoeven 
1275077365a9SGeert Uytterhoeven 	sh_pfc_enums = kcalloc(SH_PFC_MAX_ENUMS, sizeof(*sh_pfc_enums),
1276077365a9SGeert Uytterhoeven 			      GFP_KERNEL);
1277077365a9SGeert Uytterhoeven 	if (!sh_pfc_enums)
1278077365a9SGeert Uytterhoeven 		goto free_regs;
1279077365a9SGeert Uytterhoeven 
1280f4e260bfSGeert Uytterhoeven 	pr_warn("sh_pfc: Checking builtin pinmux tables\n");
1281077365a9SGeert Uytterhoeven 
1282077365a9SGeert Uytterhoeven 	for (i = 0; pdrv->id_table[i].name[0]; i++)
1283077365a9SGeert Uytterhoeven 		sh_pfc_check_info((void *)pdrv->id_table[i].driver_data);
1284077365a9SGeert Uytterhoeven 
1285077365a9SGeert Uytterhoeven #ifdef CONFIG_OF
1286077365a9SGeert Uytterhoeven 	for (i = 0; pdrv->driver.of_match_table[i].compatible[0]; i++)
1287077365a9SGeert Uytterhoeven 		sh_pfc_check_info(pdrv->driver.of_match_table[i].data);
1288077365a9SGeert Uytterhoeven #endif
1289077365a9SGeert Uytterhoeven 
1290f4e260bfSGeert Uytterhoeven 	pr_warn("sh_pfc: Detected %u errors and %u warnings\n", sh_pfc_errors,
1291077365a9SGeert Uytterhoeven 		sh_pfc_warnings);
1292077365a9SGeert Uytterhoeven 
1293077365a9SGeert Uytterhoeven 	kfree(sh_pfc_enums);
1294077365a9SGeert Uytterhoeven free_regs:
1295077365a9SGeert Uytterhoeven 	kfree(sh_pfc_regs);
1296077365a9SGeert Uytterhoeven }
1297077365a9SGeert Uytterhoeven 
1298077365a9SGeert Uytterhoeven #else /* !DEBUG */
sh_pfc_check_driver(struct platform_driver * pdrv)1299077365a9SGeert Uytterhoeven static inline void sh_pfc_check_driver(struct platform_driver *pdrv) {}
1300077365a9SGeert Uytterhoeven #endif /* !DEBUG */
1301077365a9SGeert Uytterhoeven 
sh_pfc_probe(struct platform_device * pdev)1302077365a9SGeert Uytterhoeven static int sh_pfc_probe(struct platform_device *pdev)
1303077365a9SGeert Uytterhoeven {
1304077365a9SGeert Uytterhoeven 	const struct sh_pfc_soc_info *info;
1305077365a9SGeert Uytterhoeven 	struct sh_pfc *pfc;
1306077365a9SGeert Uytterhoeven 	int ret;
1307077365a9SGeert Uytterhoeven 
130847ea7ff1SWolfram Sang 	if (pdev->dev.of_node)
1309077365a9SGeert Uytterhoeven 		info = of_device_get_match_data(&pdev->dev);
131047ea7ff1SWolfram Sang 	else
1311077365a9SGeert Uytterhoeven 		info = (const void *)platform_get_device_id(pdev)->driver_data;
1312077365a9SGeert Uytterhoeven 
1313077365a9SGeert Uytterhoeven 	pfc = devm_kzalloc(&pdev->dev, sizeof(*pfc), GFP_KERNEL);
1314077365a9SGeert Uytterhoeven 	if (pfc == NULL)
1315077365a9SGeert Uytterhoeven 		return -ENOMEM;
1316077365a9SGeert Uytterhoeven 
1317077365a9SGeert Uytterhoeven 	pfc->info = info;
1318077365a9SGeert Uytterhoeven 	pfc->dev = &pdev->dev;
1319077365a9SGeert Uytterhoeven 
1320077365a9SGeert Uytterhoeven 	ret = sh_pfc_map_resources(pfc, pdev);
1321077365a9SGeert Uytterhoeven 	if (unlikely(ret < 0))
1322077365a9SGeert Uytterhoeven 		return ret;
1323077365a9SGeert Uytterhoeven 
1324077365a9SGeert Uytterhoeven 	spin_lock_init(&pfc->lock);
1325077365a9SGeert Uytterhoeven 
1326077365a9SGeert Uytterhoeven 	if (info->ops && info->ops->init) {
1327077365a9SGeert Uytterhoeven 		ret = info->ops->init(pfc);
1328077365a9SGeert Uytterhoeven 		if (ret < 0)
1329077365a9SGeert Uytterhoeven 			return ret;
1330077365a9SGeert Uytterhoeven 
1331077365a9SGeert Uytterhoeven 		/* .init() may have overridden pfc->info */
1332077365a9SGeert Uytterhoeven 		info = pfc->info;
1333077365a9SGeert Uytterhoeven 	}
1334077365a9SGeert Uytterhoeven 
1335077365a9SGeert Uytterhoeven 	ret = sh_pfc_suspend_init(pfc);
1336077365a9SGeert Uytterhoeven 	if (ret)
1337077365a9SGeert Uytterhoeven 		return ret;
1338077365a9SGeert Uytterhoeven 
1339077365a9SGeert Uytterhoeven 	/* Enable dummy states for those platforms without pinctrl support */
1340077365a9SGeert Uytterhoeven 	if (!of_have_populated_dt())
1341077365a9SGeert Uytterhoeven 		pinctrl_provide_dummies();
1342077365a9SGeert Uytterhoeven 
1343077365a9SGeert Uytterhoeven 	ret = sh_pfc_init_ranges(pfc);
1344077365a9SGeert Uytterhoeven 	if (ret < 0)
1345077365a9SGeert Uytterhoeven 		return ret;
1346077365a9SGeert Uytterhoeven 
1347077365a9SGeert Uytterhoeven 	/*
1348077365a9SGeert Uytterhoeven 	 * Initialize pinctrl bindings first
1349077365a9SGeert Uytterhoeven 	 */
1350077365a9SGeert Uytterhoeven 	ret = sh_pfc_register_pinctrl(pfc);
1351077365a9SGeert Uytterhoeven 	if (unlikely(ret != 0))
1352077365a9SGeert Uytterhoeven 		return ret;
1353077365a9SGeert Uytterhoeven 
1354077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_SH_PFC_GPIO
1355077365a9SGeert Uytterhoeven 	/*
1356077365a9SGeert Uytterhoeven 	 * Then the GPIO chip
1357077365a9SGeert Uytterhoeven 	 */
1358077365a9SGeert Uytterhoeven 	ret = sh_pfc_register_gpiochip(pfc);
1359077365a9SGeert Uytterhoeven 	if (unlikely(ret != 0)) {
1360077365a9SGeert Uytterhoeven 		/*
1361077365a9SGeert Uytterhoeven 		 * If the GPIO chip fails to come up we still leave the
1362077365a9SGeert Uytterhoeven 		 * PFC state as it is, given that there are already
1363077365a9SGeert Uytterhoeven 		 * extant users of it that have succeeded by this point.
1364077365a9SGeert Uytterhoeven 		 */
1365077365a9SGeert Uytterhoeven 		dev_notice(pfc->dev, "failed to init GPIO chip, ignoring...\n");
1366077365a9SGeert Uytterhoeven 	}
1367077365a9SGeert Uytterhoeven #endif
1368077365a9SGeert Uytterhoeven 
1369077365a9SGeert Uytterhoeven 	platform_set_drvdata(pdev, pfc);
1370077365a9SGeert Uytterhoeven 
1371077365a9SGeert Uytterhoeven 	dev_info(pfc->dev, "%s support registered\n", info->name);
1372077365a9SGeert Uytterhoeven 
1373077365a9SGeert Uytterhoeven 	return 0;
1374077365a9SGeert Uytterhoeven }
1375077365a9SGeert Uytterhoeven 
1376077365a9SGeert Uytterhoeven static const struct platform_device_id sh_pfc_id_table[] = {
1377077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7203
1378077365a9SGeert Uytterhoeven 	{ "pfc-sh7203", (kernel_ulong_t)&sh7203_pinmux_info },
1379077365a9SGeert Uytterhoeven #endif
1380077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7264
1381077365a9SGeert Uytterhoeven 	{ "pfc-sh7264", (kernel_ulong_t)&sh7264_pinmux_info },
1382077365a9SGeert Uytterhoeven #endif
1383077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7269
1384077365a9SGeert Uytterhoeven 	{ "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info },
1385077365a9SGeert Uytterhoeven #endif
1386077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7720
1387077365a9SGeert Uytterhoeven 	{ "pfc-sh7720", (kernel_ulong_t)&sh7720_pinmux_info },
1388077365a9SGeert Uytterhoeven #endif
1389077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7722
1390077365a9SGeert Uytterhoeven 	{ "pfc-sh7722", (kernel_ulong_t)&sh7722_pinmux_info },
1391077365a9SGeert Uytterhoeven #endif
1392077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7723
1393077365a9SGeert Uytterhoeven 	{ "pfc-sh7723", (kernel_ulong_t)&sh7723_pinmux_info },
1394077365a9SGeert Uytterhoeven #endif
1395077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7724
1396077365a9SGeert Uytterhoeven 	{ "pfc-sh7724", (kernel_ulong_t)&sh7724_pinmux_info },
1397077365a9SGeert Uytterhoeven #endif
1398077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7734
1399077365a9SGeert Uytterhoeven 	{ "pfc-sh7734", (kernel_ulong_t)&sh7734_pinmux_info },
1400077365a9SGeert Uytterhoeven #endif
1401077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7757
1402077365a9SGeert Uytterhoeven 	{ "pfc-sh7757", (kernel_ulong_t)&sh7757_pinmux_info },
1403077365a9SGeert Uytterhoeven #endif
1404077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7785
1405077365a9SGeert Uytterhoeven 	{ "pfc-sh7785", (kernel_ulong_t)&sh7785_pinmux_info },
1406077365a9SGeert Uytterhoeven #endif
1407077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SH7786
1408077365a9SGeert Uytterhoeven 	{ "pfc-sh7786", (kernel_ulong_t)&sh7786_pinmux_info },
1409077365a9SGeert Uytterhoeven #endif
1410077365a9SGeert Uytterhoeven #ifdef CONFIG_PINCTRL_PFC_SHX3
1411077365a9SGeert Uytterhoeven 	{ "pfc-shx3", (kernel_ulong_t)&shx3_pinmux_info },
1412077365a9SGeert Uytterhoeven #endif
14130256b6aeSGeert Uytterhoeven 	{ /* sentinel */ }
1414077365a9SGeert Uytterhoeven };
1415077365a9SGeert Uytterhoeven 
1416077365a9SGeert Uytterhoeven static struct platform_driver sh_pfc_driver = {
1417077365a9SGeert Uytterhoeven 	.probe		= sh_pfc_probe,
1418077365a9SGeert Uytterhoeven 	.id_table	= sh_pfc_id_table,
1419077365a9SGeert Uytterhoeven 	.driver		= {
1420077365a9SGeert Uytterhoeven 		.name	= DRV_NAME,
1421077365a9SGeert Uytterhoeven 		.of_match_table = of_match_ptr(sh_pfc_of_table),
142293664eb8SGeert Uytterhoeven 		.pm	= pm_psci_sleep_ptr(&sh_pfc_pm),
1423077365a9SGeert Uytterhoeven 	},
1424077365a9SGeert Uytterhoeven };
1425077365a9SGeert Uytterhoeven 
sh_pfc_init(void)1426077365a9SGeert Uytterhoeven static int __init sh_pfc_init(void)
1427077365a9SGeert Uytterhoeven {
1428077365a9SGeert Uytterhoeven 	sh_pfc_check_driver(&sh_pfc_driver);
1429077365a9SGeert Uytterhoeven 	return platform_driver_register(&sh_pfc_driver);
1430077365a9SGeert Uytterhoeven }
1431077365a9SGeert Uytterhoeven postcore_initcall(sh_pfc_init);
1432