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