1b5677d84SJochen Friedrich /*
2b5677d84SJochen Friedrich * General Purpose functions for the global management of the
3b5677d84SJochen Friedrich * 8260 Communication Processor Module.
4b5677d84SJochen Friedrich * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
5b5677d84SJochen Friedrich * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
6b5677d84SJochen Friedrich * 2.3.99 Updates
7b5677d84SJochen Friedrich *
8b5677d84SJochen Friedrich * 2006 (c) MontaVista Software, Inc.
9b5677d84SJochen Friedrich * Vitaly Bordug <vbordug@ru.mvista.com>
10b5677d84SJochen Friedrich * Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
11b5677d84SJochen Friedrich *
12b5677d84SJochen Friedrich * This file is licensed under the terms of the GNU General Public License
13b5677d84SJochen Friedrich * version 2. This program is licensed "as is" without any warranty of any
14b5677d84SJochen Friedrich * kind, whether express or implied.
15b5677d84SJochen Friedrich */
16b5677d84SJochen Friedrich
17b5677d84SJochen Friedrich /*
18b5677d84SJochen Friedrich *
19b5677d84SJochen Friedrich * In addition to the individual control of the communication
20b5677d84SJochen Friedrich * channels, there are a few functions that globally affect the
21b5677d84SJochen Friedrich * communication processor.
22b5677d84SJochen Friedrich *
23b5677d84SJochen Friedrich * Buffer descriptors must be allocated from the dual ported memory
24b5677d84SJochen Friedrich * space. The allocator for that is here. When the communication
25b5677d84SJochen Friedrich * process is reset, we reclaim the memory available. There is
26b5677d84SJochen Friedrich * currently no deallocator for this memory.
27b5677d84SJochen Friedrich */
28b5677d84SJochen Friedrich #include <linux/errno.h>
29b5677d84SJochen Friedrich #include <linux/sched.h>
30b5677d84SJochen Friedrich #include <linux/kernel.h>
31b5677d84SJochen Friedrich #include <linux/param.h>
32b5677d84SJochen Friedrich #include <linux/string.h>
33b5677d84SJochen Friedrich #include <linux/mm.h>
34b5677d84SJochen Friedrich #include <linux/interrupt.h>
35b5677d84SJochen Friedrich #include <linux/module.h>
36b5677d84SJochen Friedrich #include <linux/of.h>
37b5677d84SJochen Friedrich
38b5677d84SJochen Friedrich #include <asm/io.h>
39b5677d84SJochen Friedrich #include <asm/irq.h>
40b5677d84SJochen Friedrich #include <asm/page.h>
41b5677d84SJochen Friedrich #include <asm/cpm2.h>
42b5677d84SJochen Friedrich #include <asm/rheap.h>
43b5677d84SJochen Friedrich
44b5677d84SJochen Friedrich #include <sysdev/fsl_soc.h>
45b5677d84SJochen Friedrich
46b5677d84SJochen Friedrich cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
47b5677d84SJochen Friedrich
48b5677d84SJochen Friedrich /* We allocate this here because it is used almost exclusively for
49b5677d84SJochen Friedrich * the communication processor devices.
50b5677d84SJochen Friedrich */
51b5677d84SJochen Friedrich cpm2_map_t __iomem *cpm2_immr;
526e27cca9SGrant Likely EXPORT_SYMBOL(cpm2_immr);
53b5677d84SJochen Friedrich
54b5677d84SJochen Friedrich #define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
55b5677d84SJochen Friedrich of space for CPM as it is larger
56b5677d84SJochen Friedrich than on PQ2 */
57b5677d84SJochen Friedrich
cpm2_reset(void)58b5677d84SJochen Friedrich void __init cpm2_reset(void)
59b5677d84SJochen Friedrich {
60b5677d84SJochen Friedrich #ifdef CONFIG_PPC_85xx
61ca851c78SKumar Gala cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE);
62b5677d84SJochen Friedrich #else
63b5677d84SJochen Friedrich cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE);
64b5677d84SJochen Friedrich #endif
65b5677d84SJochen Friedrich
66b5677d84SJochen Friedrich /* Tell everyone where the comm processor resides.
67b5677d84SJochen Friedrich */
68b5677d84SJochen Friedrich cpmp = &cpm2_immr->im_cpm;
69872a15deSLaurent Pinchart
70872a15deSLaurent Pinchart #ifndef CONFIG_PPC_EARLY_DEBUG_CPM
71872a15deSLaurent Pinchart /* Reset the CPM.
72872a15deSLaurent Pinchart */
73872a15deSLaurent Pinchart cpm_command(CPM_CR_RST, 0);
74872a15deSLaurent Pinchart #endif
75b5677d84SJochen Friedrich }
76b5677d84SJochen Friedrich
77b5677d84SJochen Friedrich static DEFINE_SPINLOCK(cmd_lock);
78b5677d84SJochen Friedrich
79b5677d84SJochen Friedrich #define MAX_CR_CMD_LOOPS 10000
80b5677d84SJochen Friedrich
cpm_command(u32 command,u8 opcode)81b5677d84SJochen Friedrich int cpm_command(u32 command, u8 opcode)
82b5677d84SJochen Friedrich {
83b5677d84SJochen Friedrich int i, ret;
84b5677d84SJochen Friedrich unsigned long flags;
85b5677d84SJochen Friedrich
86b5677d84SJochen Friedrich spin_lock_irqsave(&cmd_lock, flags);
87b5677d84SJochen Friedrich
88b5677d84SJochen Friedrich ret = 0;
89b5677d84SJochen Friedrich out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG);
90b5677d84SJochen Friedrich for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
91b5677d84SJochen Friedrich if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
92b5677d84SJochen Friedrich goto out;
93b5677d84SJochen Friedrich
94e48b1b45SHarvey Harrison printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
95b5677d84SJochen Friedrich ret = -EIO;
96b5677d84SJochen Friedrich out:
97b5677d84SJochen Friedrich spin_unlock_irqrestore(&cmd_lock, flags);
98b5677d84SJochen Friedrich return ret;
99b5677d84SJochen Friedrich }
100b5677d84SJochen Friedrich EXPORT_SYMBOL(cpm_command);
101b5677d84SJochen Friedrich
102b5677d84SJochen Friedrich /* Set a baud rate generator. This needs lots of work. There are
103b5677d84SJochen Friedrich * eight BRGs, which can be connected to the CPM channels or output
104b5677d84SJochen Friedrich * as clocks. The BRGs are in two different block of internal
105b5677d84SJochen Friedrich * memory mapped space.
106b5677d84SJochen Friedrich * The baud rate clock is the system clock divided by something.
107b5677d84SJochen Friedrich * It was set up long ago during the initial boot phase and is
108738f9dcaSJason Wang * given to us.
109b5677d84SJochen Friedrich * Baud rate clocks are zero-based in the driver code (as that maps
110b5677d84SJochen Friedrich * to port numbers). Documentation uses 1-based numbering.
111b5677d84SJochen Friedrich */
__cpm2_setbrg(uint brg,uint rate,uint clk,int div16,int src)112dddb8d31SLaurent Pinchart void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
113b5677d84SJochen Friedrich {
114b5677d84SJochen Friedrich u32 __iomem *bp;
115dddb8d31SLaurent Pinchart u32 val;
116b5677d84SJochen Friedrich
117b5677d84SJochen Friedrich /* This is good enough to get SMCs running.....
118b5677d84SJochen Friedrich */
119b5677d84SJochen Friedrich if (brg < 4) {
120*7768716dSChristophe Leroy bp = &cpm2_immr->im_brgc1;
121b5677d84SJochen Friedrich } else {
122*7768716dSChristophe Leroy bp = &cpm2_immr->im_brgc5;
123b5677d84SJochen Friedrich brg -= 4;
124b5677d84SJochen Friedrich }
125b5677d84SJochen Friedrich bp += brg;
1267b890994SLaurent Pinchart /* Round the clock divider to the nearest integer. */
1277b890994SLaurent Pinchart val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
128b5677d84SJochen Friedrich if (div16)
129b5677d84SJochen Friedrich val |= CPM_BRG_DIV16;
130b5677d84SJochen Friedrich
131b5677d84SJochen Friedrich out_be32(bp, val);
132b5677d84SJochen Friedrich }
133dddb8d31SLaurent Pinchart EXPORT_SYMBOL(__cpm2_setbrg);
134b5677d84SJochen Friedrich
cpm2_clk_setup(enum cpm_clk_target target,int clock,int mode)1356c552983SNick Child int __init cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
136b5677d84SJochen Friedrich {
137b5677d84SJochen Friedrich int ret = 0;
138b5677d84SJochen Friedrich int shift;
139b5677d84SJochen Friedrich int i, bits = 0;
140b5677d84SJochen Friedrich u32 __iomem *reg;
141b5677d84SJochen Friedrich u32 mask = 7;
142b5677d84SJochen Friedrich
143b5677d84SJochen Friedrich u8 clk_map[][3] = {
144b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_BRG5, 0},
145b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_BRG6, 1},
146b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_BRG7, 2},
147b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_BRG8, 3},
148b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_CLK9, 4},
149b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_CLK10, 5},
150b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_CLK11, 6},
151b5677d84SJochen Friedrich {CPM_CLK_FCC1, CPM_CLK12, 7},
152b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_BRG5, 0},
153b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_BRG6, 1},
154b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_BRG7, 2},
155b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_BRG8, 3},
156b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_CLK13, 4},
157b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_CLK14, 5},
158b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_CLK15, 6},
159b5677d84SJochen Friedrich {CPM_CLK_FCC2, CPM_CLK16, 7},
160b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_BRG5, 0},
161b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_BRG6, 1},
162b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_BRG7, 2},
163b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_BRG8, 3},
164b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_CLK13, 4},
165b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_CLK14, 5},
166b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_CLK15, 6},
167b5677d84SJochen Friedrich {CPM_CLK_FCC3, CPM_CLK16, 7},
168b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_BRG1, 0},
169b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_BRG2, 1},
170b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_BRG3, 2},
171b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_BRG4, 3},
172b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_CLK11, 4},
173b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_CLK12, 5},
174b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_CLK3, 6},
175b5677d84SJochen Friedrich {CPM_CLK_SCC1, CPM_CLK4, 7},
176b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_BRG1, 0},
177b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_BRG2, 1},
178b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_BRG3, 2},
179b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_BRG4, 3},
180b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_CLK11, 4},
181b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_CLK12, 5},
182b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_CLK3, 6},
183b5677d84SJochen Friedrich {CPM_CLK_SCC2, CPM_CLK4, 7},
184b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_BRG1, 0},
185b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_BRG2, 1},
186b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_BRG3, 2},
187b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_BRG4, 3},
188b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_CLK5, 4},
189b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_CLK6, 5},
190b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_CLK7, 6},
191b5677d84SJochen Friedrich {CPM_CLK_SCC3, CPM_CLK8, 7},
192b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_BRG1, 0},
193b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_BRG2, 1},
194b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_BRG3, 2},
195b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_BRG4, 3},
196b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_CLK5, 4},
197b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_CLK6, 5},
198b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_CLK7, 6},
199b5677d84SJochen Friedrich {CPM_CLK_SCC4, CPM_CLK8, 7},
200b5677d84SJochen Friedrich };
201b5677d84SJochen Friedrich
202b5677d84SJochen Friedrich switch (target) {
203b5677d84SJochen Friedrich case CPM_CLK_SCC1:
204*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_scr;
205b5677d84SJochen Friedrich shift = 24;
206025306f3SLaurent Pinchart break;
207b5677d84SJochen Friedrich case CPM_CLK_SCC2:
208*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_scr;
209b5677d84SJochen Friedrich shift = 16;
210b5677d84SJochen Friedrich break;
211b5677d84SJochen Friedrich case CPM_CLK_SCC3:
212*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_scr;
213b5677d84SJochen Friedrich shift = 8;
214b5677d84SJochen Friedrich break;
215b5677d84SJochen Friedrich case CPM_CLK_SCC4:
216*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_scr;
217b5677d84SJochen Friedrich shift = 0;
218b5677d84SJochen Friedrich break;
219b5677d84SJochen Friedrich case CPM_CLK_FCC1:
220*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_fcr;
221b5677d84SJochen Friedrich shift = 24;
222b5677d84SJochen Friedrich break;
223b5677d84SJochen Friedrich case CPM_CLK_FCC2:
224*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_fcr;
225b5677d84SJochen Friedrich shift = 16;
226b5677d84SJochen Friedrich break;
227b5677d84SJochen Friedrich case CPM_CLK_FCC3:
228*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_fcr;
229b5677d84SJochen Friedrich shift = 8;
230b5677d84SJochen Friedrich break;
231b5677d84SJochen Friedrich default:
232b5677d84SJochen Friedrich printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
233b5677d84SJochen Friedrich return -EINVAL;
234b5677d84SJochen Friedrich }
235b5677d84SJochen Friedrich
236b5677d84SJochen Friedrich for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
237b5677d84SJochen Friedrich if (clk_map[i][0] == target && clk_map[i][1] == clock) {
238b5677d84SJochen Friedrich bits = clk_map[i][2];
239b5677d84SJochen Friedrich break;
240b5677d84SJochen Friedrich }
241b5677d84SJochen Friedrich }
242b5677d84SJochen Friedrich if (i == ARRAY_SIZE(clk_map))
243b5677d84SJochen Friedrich ret = -EINVAL;
244b5677d84SJochen Friedrich
245b5677d84SJochen Friedrich bits <<= shift;
246b5677d84SJochen Friedrich mask <<= shift;
247b5677d84SJochen Friedrich
2481cca2d2bSWolfgang Ocker if (mode == CPM_CLK_RTX) {
2491cca2d2bSWolfgang Ocker bits |= bits << 3;
2501cca2d2bSWolfgang Ocker mask |= mask << 3;
2511cca2d2bSWolfgang Ocker } else if (mode == CPM_CLK_RX) {
2521cca2d2bSWolfgang Ocker bits <<= 3;
2531cca2d2bSWolfgang Ocker mask <<= 3;
2541cca2d2bSWolfgang Ocker }
2551cca2d2bSWolfgang Ocker
256b5677d84SJochen Friedrich out_be32(reg, (in_be32(reg) & ~mask) | bits);
257b5677d84SJochen Friedrich
258b5677d84SJochen Friedrich return ret;
259b5677d84SJochen Friedrich }
260b5677d84SJochen Friedrich
cpm2_smc_clk_setup(enum cpm_clk_target target,int clock)2616c552983SNick Child int __init cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
262b5677d84SJochen Friedrich {
263b5677d84SJochen Friedrich int ret = 0;
264b5677d84SJochen Friedrich int shift;
265b5677d84SJochen Friedrich int i, bits = 0;
266b5677d84SJochen Friedrich u8 __iomem *reg;
267b5677d84SJochen Friedrich u8 mask = 3;
268b5677d84SJochen Friedrich
269b5677d84SJochen Friedrich u8 clk_map[][3] = {
270b5677d84SJochen Friedrich {CPM_CLK_SMC1, CPM_BRG1, 0},
271b5677d84SJochen Friedrich {CPM_CLK_SMC1, CPM_BRG7, 1},
272b5677d84SJochen Friedrich {CPM_CLK_SMC1, CPM_CLK7, 2},
273b5677d84SJochen Friedrich {CPM_CLK_SMC1, CPM_CLK9, 3},
274b5677d84SJochen Friedrich {CPM_CLK_SMC2, CPM_BRG2, 0},
275b5677d84SJochen Friedrich {CPM_CLK_SMC2, CPM_BRG8, 1},
276b5677d84SJochen Friedrich {CPM_CLK_SMC2, CPM_CLK4, 2},
277b5677d84SJochen Friedrich {CPM_CLK_SMC2, CPM_CLK15, 3},
278b5677d84SJochen Friedrich };
279b5677d84SJochen Friedrich
280b5677d84SJochen Friedrich switch (target) {
281b5677d84SJochen Friedrich case CPM_CLK_SMC1:
282*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_smr;
283b5677d84SJochen Friedrich mask = 3;
284b5677d84SJochen Friedrich shift = 4;
285b5677d84SJochen Friedrich break;
286b5677d84SJochen Friedrich case CPM_CLK_SMC2:
287*7768716dSChristophe Leroy reg = &cpm2_immr->im_cpmux.cmx_smr;
288b5677d84SJochen Friedrich mask = 3;
289b5677d84SJochen Friedrich shift = 0;
290b5677d84SJochen Friedrich break;
291b5677d84SJochen Friedrich default:
292b5677d84SJochen Friedrich printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n");
293b5677d84SJochen Friedrich return -EINVAL;
294b5677d84SJochen Friedrich }
295b5677d84SJochen Friedrich
296b5677d84SJochen Friedrich for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
297b5677d84SJochen Friedrich if (clk_map[i][0] == target && clk_map[i][1] == clock) {
298b5677d84SJochen Friedrich bits = clk_map[i][2];
299b5677d84SJochen Friedrich break;
300b5677d84SJochen Friedrich }
301b5677d84SJochen Friedrich }
302b5677d84SJochen Friedrich if (i == ARRAY_SIZE(clk_map))
303b5677d84SJochen Friedrich ret = -EINVAL;
304b5677d84SJochen Friedrich
305b5677d84SJochen Friedrich bits <<= shift;
306b5677d84SJochen Friedrich mask <<= shift;
307b5677d84SJochen Friedrich
308b5677d84SJochen Friedrich out_8(reg, (in_8(reg) & ~mask) | bits);
309b5677d84SJochen Friedrich
310b5677d84SJochen Friedrich return ret;
311b5677d84SJochen Friedrich }
312b5677d84SJochen Friedrich
313b5677d84SJochen Friedrich struct cpm2_ioports {
314b5677d84SJochen Friedrich u32 dir, par, sor, odr, dat;
315b5677d84SJochen Friedrich u32 res[3];
316b5677d84SJochen Friedrich };
317b5677d84SJochen Friedrich
cpm2_set_pin(int port,int pin,int flags)3186c552983SNick Child void __init cpm2_set_pin(int port, int pin, int flags)
319b5677d84SJochen Friedrich {
320b5677d84SJochen Friedrich struct cpm2_ioports __iomem *iop =
321b5677d84SJochen Friedrich (struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
322b5677d84SJochen Friedrich
323b5677d84SJochen Friedrich pin = 1 << (31 - pin);
324b5677d84SJochen Friedrich
325b5677d84SJochen Friedrich if (flags & CPM_PIN_OUTPUT)
326b5677d84SJochen Friedrich setbits32(&iop[port].dir, pin);
327b5677d84SJochen Friedrich else
328b5677d84SJochen Friedrich clrbits32(&iop[port].dir, pin);
329b5677d84SJochen Friedrich
330b5677d84SJochen Friedrich if (!(flags & CPM_PIN_GPIO))
331b5677d84SJochen Friedrich setbits32(&iop[port].par, pin);
332b5677d84SJochen Friedrich else
333b5677d84SJochen Friedrich clrbits32(&iop[port].par, pin);
334b5677d84SJochen Friedrich
335b5677d84SJochen Friedrich if (flags & CPM_PIN_SECONDARY)
336b5677d84SJochen Friedrich setbits32(&iop[port].sor, pin);
337b5677d84SJochen Friedrich else
338b5677d84SJochen Friedrich clrbits32(&iop[port].sor, pin);
339b5677d84SJochen Friedrich
340b5677d84SJochen Friedrich if (flags & CPM_PIN_OPENDRAIN)
341b5677d84SJochen Friedrich setbits32(&iop[port].odr, pin);
342b5677d84SJochen Friedrich else
343b5677d84SJochen Friedrich clrbits32(&iop[port].odr, pin);
344b5677d84SJochen Friedrich }
345