162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * General Purpose functions for the global management of the
362306a36Sopenharmony_ci * 8260 Communication Processor Module.
462306a36Sopenharmony_ci * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
562306a36Sopenharmony_ci * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
662306a36Sopenharmony_ci *	2.3.99 Updates
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * 2006 (c) MontaVista Software, Inc.
962306a36Sopenharmony_ci * Vitaly Bordug <vbordug@ru.mvista.com>
1062306a36Sopenharmony_ci * 	Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License
1362306a36Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any
1462306a36Sopenharmony_ci * kind, whether express or implied.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * In addition to the individual control of the communication
2062306a36Sopenharmony_ci * channels, there are a few functions that globally affect the
2162306a36Sopenharmony_ci * communication processor.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Buffer descriptors must be allocated from the dual ported memory
2462306a36Sopenharmony_ci * space.  The allocator for that is here.  When the communication
2562306a36Sopenharmony_ci * process is reset, we reclaim the memory available.  There is
2662306a36Sopenharmony_ci * currently no deallocator for this memory.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci#include <linux/errno.h>
2962306a36Sopenharmony_ci#include <linux/sched.h>
3062306a36Sopenharmony_ci#include <linux/kernel.h>
3162306a36Sopenharmony_ci#include <linux/param.h>
3262306a36Sopenharmony_ci#include <linux/string.h>
3362306a36Sopenharmony_ci#include <linux/mm.h>
3462306a36Sopenharmony_ci#include <linux/interrupt.h>
3562306a36Sopenharmony_ci#include <linux/module.h>
3662306a36Sopenharmony_ci#include <linux/of.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <asm/io.h>
3962306a36Sopenharmony_ci#include <asm/irq.h>
4062306a36Sopenharmony_ci#include <asm/page.h>
4162306a36Sopenharmony_ci#include <asm/cpm2.h>
4262306a36Sopenharmony_ci#include <asm/rheap.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <sysdev/fsl_soc.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cicpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* We allocate this here because it is used almost exclusively for
4962306a36Sopenharmony_ci * the communication processor devices.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cicpm2_map_t __iomem *cpm2_immr;
5262306a36Sopenharmony_ciEXPORT_SYMBOL(cpm2_immr);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3 reserve this amount
5562306a36Sopenharmony_ci					   of space for CPM as it is larger
5662306a36Sopenharmony_ci					   than on PQ2 */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_civoid __init cpm2_reset(void)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci#ifdef CONFIG_PPC_85xx
6162306a36Sopenharmony_ci	cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE);
6262306a36Sopenharmony_ci#else
6362306a36Sopenharmony_ci	cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE);
6462306a36Sopenharmony_ci#endif
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Tell everyone where the comm processor resides.
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	cpmp = &cpm2_immr->im_cpm;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#ifndef CONFIG_PPC_EARLY_DEBUG_CPM
7162306a36Sopenharmony_ci	/* Reset the CPM.
7262306a36Sopenharmony_ci	 */
7362306a36Sopenharmony_ci	cpm_command(CPM_CR_RST, 0);
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cmd_lock);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define MAX_CR_CMD_LOOPS        10000
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciint cpm_command(u32 command, u8 opcode)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	int i, ret;
8462306a36Sopenharmony_ci	unsigned long flags;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	spin_lock_irqsave(&cmd_lock, flags);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = 0;
8962306a36Sopenharmony_ci	out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG);
9062306a36Sopenharmony_ci	for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
9162306a36Sopenharmony_ci		if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
9262306a36Sopenharmony_ci			goto out;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
9562306a36Sopenharmony_ci	ret = -EIO;
9662306a36Sopenharmony_ciout:
9762306a36Sopenharmony_ci	spin_unlock_irqrestore(&cmd_lock, flags);
9862306a36Sopenharmony_ci	return ret;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ciEXPORT_SYMBOL(cpm_command);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/* Set a baud rate generator.  This needs lots of work.  There are
10362306a36Sopenharmony_ci * eight BRGs, which can be connected to the CPM channels or output
10462306a36Sopenharmony_ci * as clocks.  The BRGs are in two different block of internal
10562306a36Sopenharmony_ci * memory mapped space.
10662306a36Sopenharmony_ci * The baud rate clock is the system clock divided by something.
10762306a36Sopenharmony_ci * It was set up long ago during the initial boot phase and is
10862306a36Sopenharmony_ci * given to us.
10962306a36Sopenharmony_ci * Baud rate clocks are zero-based in the driver code (as that maps
11062306a36Sopenharmony_ci * to port numbers).  Documentation uses 1-based numbering.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_civoid __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	u32 __iomem *bp;
11562306a36Sopenharmony_ci	u32 val;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* This is good enough to get SMCs running.....
11862306a36Sopenharmony_ci	*/
11962306a36Sopenharmony_ci	if (brg < 4) {
12062306a36Sopenharmony_ci		bp = &cpm2_immr->im_brgc1;
12162306a36Sopenharmony_ci	} else {
12262306a36Sopenharmony_ci		bp = &cpm2_immr->im_brgc5;
12362306a36Sopenharmony_ci		brg -= 4;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	bp += brg;
12662306a36Sopenharmony_ci	/* Round the clock divider to the nearest integer. */
12762306a36Sopenharmony_ci	val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
12862306a36Sopenharmony_ci	if (div16)
12962306a36Sopenharmony_ci		val |= CPM_BRG_DIV16;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	out_be32(bp, val);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL(__cpm2_setbrg);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint __init cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	int ret = 0;
13862306a36Sopenharmony_ci	int shift;
13962306a36Sopenharmony_ci	int i, bits = 0;
14062306a36Sopenharmony_ci	u32 __iomem *reg;
14162306a36Sopenharmony_ci	u32 mask = 7;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	u8 clk_map[][3] = {
14462306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_BRG5, 0},
14562306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_BRG6, 1},
14662306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_BRG7, 2},
14762306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_BRG8, 3},
14862306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_CLK9, 4},
14962306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_CLK10, 5},
15062306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_CLK11, 6},
15162306a36Sopenharmony_ci		{CPM_CLK_FCC1, CPM_CLK12, 7},
15262306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_BRG5, 0},
15362306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_BRG6, 1},
15462306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_BRG7, 2},
15562306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_BRG8, 3},
15662306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_CLK13, 4},
15762306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_CLK14, 5},
15862306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_CLK15, 6},
15962306a36Sopenharmony_ci		{CPM_CLK_FCC2, CPM_CLK16, 7},
16062306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_BRG5, 0},
16162306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_BRG6, 1},
16262306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_BRG7, 2},
16362306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_BRG8, 3},
16462306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_CLK13, 4},
16562306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_CLK14, 5},
16662306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_CLK15, 6},
16762306a36Sopenharmony_ci		{CPM_CLK_FCC3, CPM_CLK16, 7},
16862306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_BRG1, 0},
16962306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_BRG2, 1},
17062306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_BRG3, 2},
17162306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_BRG4, 3},
17262306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_CLK11, 4},
17362306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_CLK12, 5},
17462306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_CLK3, 6},
17562306a36Sopenharmony_ci		{CPM_CLK_SCC1, CPM_CLK4, 7},
17662306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_BRG1, 0},
17762306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_BRG2, 1},
17862306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_BRG3, 2},
17962306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_BRG4, 3},
18062306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_CLK11, 4},
18162306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_CLK12, 5},
18262306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_CLK3, 6},
18362306a36Sopenharmony_ci		{CPM_CLK_SCC2, CPM_CLK4, 7},
18462306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_BRG1, 0},
18562306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_BRG2, 1},
18662306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_BRG3, 2},
18762306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_BRG4, 3},
18862306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_CLK5, 4},
18962306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_CLK6, 5},
19062306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_CLK7, 6},
19162306a36Sopenharmony_ci		{CPM_CLK_SCC3, CPM_CLK8, 7},
19262306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_BRG1, 0},
19362306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_BRG2, 1},
19462306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_BRG3, 2},
19562306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_BRG4, 3},
19662306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_CLK5, 4},
19762306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_CLK6, 5},
19862306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_CLK7, 6},
19962306a36Sopenharmony_ci		{CPM_CLK_SCC4, CPM_CLK8, 7},
20062306a36Sopenharmony_ci	};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	switch (target) {
20362306a36Sopenharmony_ci	case CPM_CLK_SCC1:
20462306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_scr;
20562306a36Sopenharmony_ci		shift = 24;
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case CPM_CLK_SCC2:
20862306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_scr;
20962306a36Sopenharmony_ci		shift = 16;
21062306a36Sopenharmony_ci		break;
21162306a36Sopenharmony_ci	case CPM_CLK_SCC3:
21262306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_scr;
21362306a36Sopenharmony_ci		shift = 8;
21462306a36Sopenharmony_ci		break;
21562306a36Sopenharmony_ci	case CPM_CLK_SCC4:
21662306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_scr;
21762306a36Sopenharmony_ci		shift = 0;
21862306a36Sopenharmony_ci		break;
21962306a36Sopenharmony_ci	case CPM_CLK_FCC1:
22062306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_fcr;
22162306a36Sopenharmony_ci		shift = 24;
22262306a36Sopenharmony_ci		break;
22362306a36Sopenharmony_ci	case CPM_CLK_FCC2:
22462306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_fcr;
22562306a36Sopenharmony_ci		shift = 16;
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	case CPM_CLK_FCC3:
22862306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_fcr;
22962306a36Sopenharmony_ci		shift = 8;
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	default:
23262306a36Sopenharmony_ci		printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
23362306a36Sopenharmony_ci		return -EINVAL;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
23762306a36Sopenharmony_ci		if (clk_map[i][0] == target && clk_map[i][1] == clock) {
23862306a36Sopenharmony_ci			bits = clk_map[i][2];
23962306a36Sopenharmony_ci			break;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci	if (i == ARRAY_SIZE(clk_map))
24362306a36Sopenharmony_ci	    ret = -EINVAL;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	bits <<= shift;
24662306a36Sopenharmony_ci	mask <<= shift;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (mode == CPM_CLK_RTX) {
24962306a36Sopenharmony_ci		bits |= bits << 3;
25062306a36Sopenharmony_ci		mask |= mask << 3;
25162306a36Sopenharmony_ci	} else if (mode == CPM_CLK_RX) {
25262306a36Sopenharmony_ci		bits <<= 3;
25362306a36Sopenharmony_ci		mask <<= 3;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	out_be32(reg, (in_be32(reg) & ~mask) | bits);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return ret;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ciint __init cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	int ret = 0;
26462306a36Sopenharmony_ci	int shift;
26562306a36Sopenharmony_ci	int i, bits = 0;
26662306a36Sopenharmony_ci	u8 __iomem *reg;
26762306a36Sopenharmony_ci	u8 mask = 3;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	u8 clk_map[][3] = {
27062306a36Sopenharmony_ci		{CPM_CLK_SMC1, CPM_BRG1, 0},
27162306a36Sopenharmony_ci		{CPM_CLK_SMC1, CPM_BRG7, 1},
27262306a36Sopenharmony_ci		{CPM_CLK_SMC1, CPM_CLK7, 2},
27362306a36Sopenharmony_ci		{CPM_CLK_SMC1, CPM_CLK9, 3},
27462306a36Sopenharmony_ci		{CPM_CLK_SMC2, CPM_BRG2, 0},
27562306a36Sopenharmony_ci		{CPM_CLK_SMC2, CPM_BRG8, 1},
27662306a36Sopenharmony_ci		{CPM_CLK_SMC2, CPM_CLK4, 2},
27762306a36Sopenharmony_ci		{CPM_CLK_SMC2, CPM_CLK15, 3},
27862306a36Sopenharmony_ci	};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	switch (target) {
28162306a36Sopenharmony_ci	case CPM_CLK_SMC1:
28262306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_smr;
28362306a36Sopenharmony_ci		mask = 3;
28462306a36Sopenharmony_ci		shift = 4;
28562306a36Sopenharmony_ci		break;
28662306a36Sopenharmony_ci	case CPM_CLK_SMC2:
28762306a36Sopenharmony_ci		reg = &cpm2_immr->im_cpmux.cmx_smr;
28862306a36Sopenharmony_ci		mask = 3;
28962306a36Sopenharmony_ci		shift = 0;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	default:
29262306a36Sopenharmony_ci		printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n");
29362306a36Sopenharmony_ci		return -EINVAL;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
29762306a36Sopenharmony_ci		if (clk_map[i][0] == target && clk_map[i][1] == clock) {
29862306a36Sopenharmony_ci			bits = clk_map[i][2];
29962306a36Sopenharmony_ci			break;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci	if (i == ARRAY_SIZE(clk_map))
30362306a36Sopenharmony_ci	    ret = -EINVAL;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	bits <<= shift;
30662306a36Sopenharmony_ci	mask <<= shift;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	out_8(reg, (in_8(reg) & ~mask) | bits);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return ret;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistruct cpm2_ioports {
31462306a36Sopenharmony_ci	u32 dir, par, sor, odr, dat;
31562306a36Sopenharmony_ci	u32 res[3];
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_civoid __init cpm2_set_pin(int port, int pin, int flags)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct cpm2_ioports __iomem *iop =
32162306a36Sopenharmony_ci		(struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	pin = 1 << (31 - pin);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (flags & CPM_PIN_OUTPUT)
32662306a36Sopenharmony_ci		setbits32(&iop[port].dir, pin);
32762306a36Sopenharmony_ci	else
32862306a36Sopenharmony_ci		clrbits32(&iop[port].dir, pin);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (!(flags & CPM_PIN_GPIO))
33162306a36Sopenharmony_ci		setbits32(&iop[port].par, pin);
33262306a36Sopenharmony_ci	else
33362306a36Sopenharmony_ci		clrbits32(&iop[port].par, pin);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (flags & CPM_PIN_SECONDARY)
33662306a36Sopenharmony_ci		setbits32(&iop[port].sor, pin);
33762306a36Sopenharmony_ci	else
33862306a36Sopenharmony_ci		clrbits32(&iop[port].sor, pin);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (flags & CPM_PIN_OPENDRAIN)
34162306a36Sopenharmony_ci		setbits32(&iop[port].odr, pin);
34262306a36Sopenharmony_ci	else
34362306a36Sopenharmony_ci		clrbits32(&iop[port].odr, pin);
34462306a36Sopenharmony_ci}
345