关于GPIO, 我懂的不多

来源:互联网 发布:js 支持base64编码 编辑:程序博客网 时间:2024/05/18 00:07

居然快一年没有更新博客了,近段时间看了下以前的一些笔记,发现做过的项目,学习的知识都忘了差不多,其实还是应该抽点时间出来记录下。

当然先列出参考文章:

http://blog.chinaunix.net/uid-27717694-id-3624294.html                     GPIO的驱动模型
http://www.wowotech.net/gpio_subsystem/io-port-control.html             linux内核中的GPIO系统之(1):软件框架

使用芯片平台 mdm9x07.

GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[].当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数
表示一个gpio口,含对应的gpio_chip.

对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等

gpio描述符struct gpio_desc {struct gpio_chip*chip;unsigned longflags;/* flag symbols are bit numbers */#define FLAG_REQUESTED0//GPIO 申请的标志,已申请的话该标志是1,否则是0#define FLAG_IS_OUT1#define FLAG_EXPORT2/* protected by sysfs_lock */#define FLAG_SYSFS3/* exported via /sys/class/gpio/control */#define FLAG_TRIG_FALL4/* trigger on falling edge */#define FLAG_TRIG_RISE5/* trigger on rising edge */#define FLAG_ACTIVE_LOW6/* value has active low */#define FLAG_OPEN_DRAIN7/* Gpio is open drain type */#define FLAG_OPEN_SOURCE 8/* Gpio is open source type */#define FLAG_USED_AS_IRQ 9/* GPIO is connected to an IRQ */#define ID_SHIFT16/* add new flags before this one */#define GPIO_FLAGS_MASK((1 << ID_SHIFT) - 1)#define GPIO_TRIGGER_MASK(BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))const char*label;};

static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];     --- 采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio

#define ARCH_NR_GPIOS        512                        --- 即系统现在有144个GPIO口


通过这个结构抽象化所有的GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO

struct gpio_chip{const char*label;struct device*dev;struct module*owner;struct list_head    list;int(*request)(struct gpio_chip *chip,unsigned offset);//请求gpiovoid(*free)(struct gpio_chip *chip,unsigned offset);//释放gpioint(*get_direction)(struct gpio_chip *chip,unsigned offset);//获取方向int(*direction_input)(struct gpio_chip *chip,unsigned offset);//配置gpio为输入,返回当前gpio状态int(*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//配置gpio为输出,并设置为valueint(*get)(struct gpio_chip *chip,unsigned offset);//获取gpio的状态void(*set)(struct gpio_chip *chip,unsigned offset, int value);//设置gpio为value值int(*set_debounce)(struct gpio_chip *chip,unsigned offset,unsigned debounce);//设置消抖动时间,尤其是gpio按键时有用int(*to_irq)(struct gpio_chip *chip,unsigned offset);//把gpio号转换为中断号void(*dbg_show)(struct seq_file *s,struct gpio_chip *chip);intbase;// 这个gpio控制器的gpio开始编号u16ngpio;//这个gpio控制器说控制的gpio数struct gpio_desc*desc;const char*const *names;boolcan_sleep;boolirq_not_threaded;boolexported;#ifdef CONFIG_GPIOLIB_IRQCHIPstruct irq_chip*irqchip;struct irq_domain*irqdomain;unsigned intirq_base;irq_flow_handler_tirq_handler;unsigned intirq_default_type;#endif#if defined(CONFIG_OF_GPIO)struct device_node *of_node;int of_gpio_n_cells;int (*of_xlate)(struct gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags);#endif#ifdef CONFIG_PINCTRLstruct list_head pin_ranges;#endif}

开始一些有用的命令了

cat /sys/kernel/debug/gpio
这个命令可以得到全部GPIO的状态

具体代码分析如下:

gpiolib.cstatic int __init gpiolib_debugfs_init(void)(void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,NULL, NULL, &gpiolib_operations);static const struct file_operations gpiolib_operations = {.owner= THIS_MODULE,.open= gpiolib_open,.read= seq_read,.llseek= seq_lseek,.release= seq_release,};static int gpiolib_open(struct inode *inode, struct file *file)return seq_open(file, &gpiolib_seq_ops);static const struct seq_operations gpiolib_seq_ops = {.start = gpiolib_seq_start,.next = gpiolib_seq_next,.stop = gpiolib_seq_stop,.show = gpiolib_seq_show,};static int gpiolib_seq_show(struct seq_file *s, void *v)struct gpio_chip *chip = v;seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,chip->base, chip->base + chip->ngpio - 1);--- 即 GPIOs 0-79dev = chip->dev;seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",dev_name(dev));--- 即 platform/1000000.pinctrlseq_printf(s, ", %s", chip->label);--- 即 , 1000000.pinctrlseq_printf(s, ":\n");--- 即 GPIOs 0-79, platform/1000000.pinctrl, 1000000.pinctrl:chip->dbg_show(s, chip);Pinctrl-msm.c (drivers\pinctrl\qcom)static struct gpio_chip msm_gpio_template = {.direction_input  = msm_gpio_direction_input,.direction_output = msm_gpio_direction_output,.get              = msm_gpio_get,.set              = msm_gpio_set,.request          = msm_gpio_request,.free             = msm_gpio_free,.dbg_show         = msm_gpio_dbg_show,};static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)for (i = 0; i < chip->ngpio; i++, gpio++) msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);static void msm_gpio_dbg_show_one(struct seq_file *s,struct pinctrl_dev *pctldev,struct gpio_chip *chip,unsigned offset,unsigned gpio)--------------重要,待分析struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);g = &pctrl->soc->groups[offset];ctl_reg = readl(pctrl->regs + g->ctl_reg);is_out = !!(ctl_reg & BIT(g->oe_bit));func = (ctl_reg >> g->mux_bit) & 7;drive = (ctl_reg >> g->drv_bit) & 7;pull = (ctl_reg >> g->pull_bit) & 3;seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);---  gpio0   : in  1seq_printf(s, " %dmA", msm_regval_to_drive(drive));---  2mAseq_printf(s, " %s", pulls[pull]);---  no pull   ,即综上  gpio0   : in  1 2mA no pull

根据 mdm9x28\kernel\Documentation\gpio\sysfs.txt 这个文档知道如何操作单个GPIO:

echo 1 > /sys/class/gpio/export   --- export GPIO1echo out > /sys/class/gpio/gpio1/direction--- 设置为输出echo 1 > /sys/class/gpio/gpio1/value--- 高电平echo in > /sys/class/gpio/gpio1/direction--- 设置为输入cat /sys/class/gpio/gpio1/value--- 读出GPIO值

动态调试,打印 pr_debug:

echo -n 'file gpiolib.c +p' > /sys/kernel/debug/dynamic_debug/control

让系统奔溃,生成dump文件看log:

echo "c" > /proc/sysrq-trigger

对于GPIO,其实最好的调试方法是直接操作寄存器,devmem 便可以,网上可以搜下源码,和配置方法。

根据 Datasheet知道0x01000000+0x1000*n   GPIO_CONFIG0x01000004+0x1000*n   GPIO_IN_OUTGPIO16:0x1010000GPIO36:0x1024000GPIO37:0x1025000写寄存器/ # devmem 0x1024000 w 0x201/dev/mem opened.Memory mapped at address 0xb6f4b000.Value at address 0x1024000 (0xb6f4b000): 0x207Written 0x201; readback 0x201读寄存器/ # devmem 0x1024000/dev/mem opened.Memory mapped at address 0xb6eff000.Value at address 0x1024000 (0xb6eff000): 0x201

sysfs 的 DEVICE_ATTR 接口,就是/sys/class/gpio/gpio1 目录下的 direction value等属性

例如:static DEVICE_ATTR(value, 0644,gpio_value_show, gpio_value_store);原型include/linux/device.h#define DEVICE_ATTR(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)_show表示的是读方法,_stroe表示的是写方法


关于 GPIO export 过程:

Gpiolib-sysfs.c (drivers\gpio)postcore_initcall(gpiolib_sysfs_init);static int __init gpiolib_sysfs_init(void)class_register(&gpio_class);--- 11:static struct class gpio_class = {.name ="gpio",.owner =THIS_MODULE,.class_attrs =gpio_class_attrs,};static struct class_attribute gpio_class_attrs[] = {__ATTR(export, 0200, NULL, export_store),__ATTR(unexport, 0200, NULL, unexport_store),__ATTR_NULL,};static ssize_t export_store(struct class *class,struct class_attribute *attr,const char *buf, size_t len)desc = gpio_to_desc(gpio);          --- &gpio_desc[gpio];  返回对应的GPIO描述符结构 status = gpiod_request(desc, "sysfs");    --- 1.1,可知 status = 0status = gpiod_export(desc, true);  --- 1.21.1:int gpiod_request(struct gpio_desc *desc, const char *label)--- GPIO 的申请__gpiod_request(desc, label);static int __gpiod_request(struct gpio_desc *desc, const char *label)if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0)--- 判断 GPIO 是否被申请if (chip->request) --- msm_gpio_request ,到底是高通的还是pinctl的? 推测应该是 pinctl的if (chip->get_direction) 1.2:int gpiod_export(struct gpio_desc *desc, bool direction_may_change)offset = gpio_chip_hwgpio(desc);dev = device_create_with_groups(&gpio_class, desc->chip->dev,1.2.1MKDEV(0, 0), desc, gpio_groups,ioname ? ioname : "gpio%u",desc_to_gpio(desc));1.2,1:struct device *device_create_with_groups(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, ...)dev = device_create_groups_vargs(class, parent, devt, drvdata, groups,fmt, vargs);device_create_file(dev, &dev_attr_direction);device_create_groups_vargs(struct class *class, struct device *parent,   dev_t devt, void *drvdata,   const struct attribute_group **groups,   const char *fmt, va_list args)device_initialize(dev);dev->devt = devt;dev->class = class;dev->parent = parent;dev->groups = groups;dev->release = device_create_release;dev_set_drvdata(dev, drvdata);retval = kobject_set_name_vargs(&dev->kobj, fmt, args);retval = device_add(dev);

关于 GPIO 的 pinctrl:

tlmm_pinmux: pinctrl@1000000 {compatible = "qcom,mdm9607-pinctrl";reg = <0x1000000 0x300000>;interrupts = <0 208 0>;...}*******pinctrl-mdm9607.c (drivers\pinctrl\qcom)arch_initcall(mdm9607_pinctrl_init);static int __init mdm9607_pinctrl_init(void)platform_driver_register(&mdm9607_pinctrl_driver);static struct platform_driver mdm9607_pinctrl_driver = {.driver = {.name = "mdm9607-pinctrl",.owner = THIS_MODULE,.of_match_table = mdm9607_pinctrl_of_match,},.probe = mdm9607_pinctrl_probe,.remove = msm_pinctrl_remove,};static int mdm9607_pinctrl_probe(struct platform_device *pdev)msm_pinctrl_probe(pdev, &mdm9607_pinctrl);static const struct msm_pinctrl_soc_data mdm9607_pinctrl = {9607 soc  的资源.pins = mdm9607_pins,.npins = ARRAY_SIZE(mdm9607_pins),.functions = mdm9607_functions,.nfunctions = ARRAY_SIZE(mdm9607_functions),.groups = mdm9607_groups,.ngroups = ARRAY_SIZE(mdm9607_groups),.ngpios = 80,};static const struct msm_pingroup mdm9607_groups[] = {PINGROUP(0, blsp_uart3, blsp_spi3, NA, NA, NA, NA, NA,qdss_tracedata_a, NA),...}#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\{        \.name = "gpio" #id,\.pins = gpio##id##_pins,\.npins = (unsigned)ARRAY_SIZE(gpio##id##_pins),\.funcs = (int[]){\msm_mux_gpio, /* gpio mode */\msm_mux_##f1,\msm_mux_##f2,\msm_mux_##f3,\msm_mux_##f4,\msm_mux_##f5,\msm_mux_##f6,\msm_mux_##f7,\msm_mux_##f8,\msm_mux_##f9\},        \.nfuncs = 10,\.ctl_reg = REG_BASE + REG_SIZE * id,        \.io_reg = REG_BASE + 0x4 + REG_SIZE * id,\.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,\.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,\.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,\.mux_bit = 2,\.pull_bit = 0,\.drv_bit = 6,\.oe_bit = 9,\.in_bit = 0,\.out_bit = 1,\.intr_enable_bit = 0,\.intr_status_bit = 0,\.intr_target_bit = 5,\.intr_target_kpss_val = 4,\.intr_raw_status_bit = 4,\.intr_polarity_bit = 1,\.intr_detection_bit = 2,\.intr_detection_width = 2,\}struct msm_pingroup {const char *name;const unsigned *pins;unsigned npins;unsigned *funcs;unsigned nfuncs;u32 ctl_reg;u32 io_reg;u32 intr_cfg_reg;u32 intr_status_reg;u32 intr_target_reg;unsigned mux_bit:5;unsigned pull_bit:5;unsigned drv_bit:5;unsigned oe_bit:5;unsigned in_bit:5;unsigned out_bit:5;unsigned intr_enable_bit:5;unsigned intr_status_bit:5;unsigned intr_ack_high:1;unsigned intr_target_bit:5;unsigned intr_target_kpss_val:5;unsigned intr_raw_status_bit:5;unsigned intr_polarity_bit:5;unsigned intr_detection_bit:5;unsigned intr_detection_width:5;};pinctrl-msm.cint msm_pinctrl_probe(struct platform_device *pdev,const struct msm_pinctrl_soc_data *soc_data)pctrl->dev = &pdev->dev;pctrl->soc = soc_data;pctrl->chip = msm_gpio_template;--- 1 ,分配 gpio_chip 的相关函数res = platform_get_resource(pdev, IORESOURCE_MEM, 0);--- 分配 memory 资源pctrl->regs = devm_ioremap_resource(&pdev->dev, res);msm_pinctrl_setup_pm_reset(pctrl);msm_pinctrl_desc.name = dev_name(&pdev->dev);msm_pinctrl_desc.pins = pctrl->soc->pins;msm_pinctrl_desc.npins = pctrl->soc->npins;pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl);ret = msm_gpio_init(pctrl)--- 21:static struct gpio_chip msm_gpio_template = {--- GPIO 最终调用的函数 ??.direction_input  = msm_gpio_direction_input,---1.2.direction_output = msm_gpio_direction_output,.get              = msm_gpio_get,.set              = msm_gpio_set,.request          = msm_gpio_request,---1.1.free             = msm_gpio_free,.dbg_show         = msm_gpio_dbg_show,};2:static int msm_gpio_init(struct msm_pinctrl *pctrl)chip = &pctrl->chip;chip->base = 0;chip->ngpio = ngpio;chip->label = dev_name(pctrl->dev);chip->dev = pctrl->dev;chip->owner = THIS_MODULE;chip->of_node = pctrl->dev->of_node;ret = gpiochip_add(&pctrl->chip);ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);1.1:static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)int gpio = chip->base + offset;return pinctrl_request_gpio(gpio);core.cint pinctrl_request_gpio(unsigned gpio)ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);static int pinctrl_get_device_gpio_range(unsigned gpio,struct pinctrl_dev **outdev,struct pinctrl_gpio_range **outrange)list_for_each_entry(pctldev, &pinctrldev_list, node) struct pinctrl_gpio_range *range;range = pinctrl_match_gpio_range(pctldev, gpio);if (range != NULL) *outdev = pctldev;*outrange = range;1.2:static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)pctrl = container_of(chip, struct msm_pinctrl, chip);g = &pctrl->soc->groups[offset];val = readl(pctrl->regs + g->ctl_reg);val &= ~BIT(g->oe_bit);writel(val, pctrl->regs + g->ctl_reg);

--------------------------------------------------------------

其实也可以从modem侧操作GPIO。

下面简要分析下 modem 这边GPIO的配置过程,例如获取GPIO1的配置情况:

DALResult TLMM_GetCurrentConfig(TLMMClientCtxt* pCtxt,uint32 nGpioNumber, DALGpioSignalType* eGpioConfig) --- 即 TLMM_GetCurrentConfig(bstlmmhp,1, gpio_config)HAL_tlmm_GetConfig(1, &tTempCurrent)*eGpioConfig = DALTLMMState_StructToMacro(nGpioNumber, &tTempCurrent);****void HAL_tlmm_GetConfig(uint32 nGpioNumber, HAL_tlmm_GpioType* tGpio)---即 HAL_tlmm_GetConfig(1, &tTempCurrent)--- nTempConfig 是一个指针指向地址的值,而这个指针指向 0x1000 1000 这个地址,即 nTempConfig 是 0x1000 1000 地址的值 nTempConfig =  HWIO_TLMM_GPIO_CFGn_INI(tHALTLMMInit.nBaseAddress, nGpioNumber);--- 即 HWIO_TLMM_GPIO_CFGn_INI(tHALTLMMInit.nBaseAddress,1)tGpio->nFunc =  ((nTempConfig &  HWIO_TLMM_GPIO_CFGn_FUNC_SEL_BMSK)>> HWIO_TLMM_GPIO_CFGn_FUNC_SEL_SHFT); --- 即 (nTempConfig&0x3c) >>2,0x3c=0011 1100 [5:2] ,为 FUNC_SELtGpio->nDir =   ((nTempConfig &  HWIO_TLMM_GPIO_CFGn_GPIO_OE_BMSK)>> HWIO_TLMM_GPIO_CFGn_GPIO_OE_SHFT);--- 即 (nTempConfig&0x200)>>9, 0x200=10 0000 0000 [10],为 GPIO_HIHYS_ENtGpio->nPull =  ((nTempConfig &  HWIO_TLMM_GPIO_CFGn_GPIO_PULL_BMSK)>> HWIO_TLMM_GPIO_CFGn_GPIO_PULL_SHFT);--- 即 (nTempConfig&0x3) >>0,0x3= 0011 [1:0] ,为 GPIO_PULLtGpio->nDrive = ((nTempConfig &  HWIO_TLMM_GPIO_CFGn_DRV_STRENGTH_BMSK)>>  HWIO_TLMM_GPIO_CFGn_DRV_STRENGTH_SHFT);--即(nTempConfig&0x1c0)>>6,0x1c0=1 1100 0000 [8:6],为 DRV_STRENGTH#define HWIO_TLMM_GPIO_CFGn_INI(base,n)        \        in_dword_masked(HWIO_TLMM_GPIO_CFGn_ADDR(base,n), HWIO_TLMM_GPIO_CFGn_RMSK)---- 即 in_dword_masked(0x1000 1000,0x7ff)#define HWIO_TLMM_GPIO_CFGn_ADDR(base,n)  ((base) + 0x00000000 + 0x1000 * (n))  ---- 即 0x1000 0000 + 0x1000 = 0x1000 1000#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask)) ---- 即 0x1000 1000 & 0x7ff = 0x1000 1000#define __inpdw(port)       (*((volatile uint32 *) (port)))----  地址 port 强制类型转换为指针,那么 __inpdw(port) 就是指向地址port 的值****DALGpioSignalType DALTLMMState_StructToMacro(uint32 nGpioNumber,HAL_tlmm_GpioType* ptState)---- 即 DALTLMMState_StructToMacro(1,&tGpio)DAL_GPIO_CFG(1,ptState->nFunc,ptState->nDir,ptState->nPull,ptState->nDrive)#define DAL_GPIO_CFG(gpio, func, dir, pull, drive) \         (((gpio) & 0x3FF)<< 4 | \          ((func) & 0xF)|        \          ((dir)  & 0x1) << 14|  \          ((pull) & 0x3) << 15|  \          ((drive)& 0xF) << 17| DAL_GPIO_VERSION)#define DAL_GPIO_VERSION 0x20000000                                              即 0010 0000 000|0 000|0 0|0|00 0000 0000 | 0000drive pull dir  gpio func  即获取 gpiocfg 成功PS:在 mdm9x40/modem_proc/core/kernel/qurt_mba/doxapi/api_doc_config_file 文件里有 DOXYGEN_SHOULD_SKIP_THIS 的定义**************_global void bsgpioread(DALGpioSignalType gpio,DALGpioValueType * pval)----读取 gpio val 值  if (bstlmmhp != NULL)    (void)DalTlmm_GpioIn(bstlmmhp, gpio, pval);---- 即 DalTlmm_GpioIn(bstlmmhp, gpiocfg, pval)static __inline DALResultDalTlmm_GpioIn(  DalDeviceHandle *_h,   DALGpioSignalType gpio_config,   DALGpioValueType*value){   if(DALISREMOTEHANDLE(_h))?????????   {      DalRemoteHandle *hRemote = (DalRemoteHandle *)DALPREPREMOTEHANDLE(_h);      return hRemote->pVtbl->FCN_2(        DALVTBLIDX(((DalTlmmHandle *)_h)->pVtbl, GpioIn ),         _h, gpio_config, (uint32*)value);   }   return ((DalTlmmHandle *)_h)->pVtbl->GpioIn( _h, gpio_config, value);---- 到这里已经不知道如何调用了,即 DAL 和 HAL 层借口如何连接???}...DDITlmm.h (core\api\systemdrivers)struct DalTlmm{   struct DalDevice DalDevice;   DALResult (*ConfigGpio)(DalDeviceHandle * _h, DALGpioSignalType gpio_config, DALGpioEnableType enable);   ...   DALResult (*GpioIn)(DalDeviceHandle * _h, DALGpioSignalType gpio_config, DALGpioValueType*  value);---------------   DALResult (*GpioOut)(DalDeviceHandle * _h, DALGpioSignalType gpio_config, DALGpioValueType value);}DALTLMMFwk.c (core\systemdrivers\tlmm\src)TLMM_DalTlmm_Attach(const char *pszArg, DALDEVICEID DeviceId,DalDeviceHandle **phDalDevice)TLMM_InitInterface(pClientCtxt);*phDalDevice = (DalDeviceHandle *)&(pClientCtxt->DalTlmmHandle);static void TLMM_InitInterface(TLMMClientCtxt* pclientCtxt)static const DalTlmm vtbl ={{}        TLMM_DalTlmm_ConfigGpio,...        TLMM_DalTlmm_GpioIn ,----------- 从上面的 DalTlmm 结构体可知道 DAL 层的 GpioIn 对应 HAL 层的 TLMM_DalTlmm_GpioIn ,        TLMM_DalTlmm_GpioOut,}pclientCtxt->DalTlmmHandle.pVtbl  = &vtbl;TLMM_DalTlmm_GpioIn( DalDeviceHandle * h, DALGpioSignalType gpio_config, DALGpioValueType* value) ---- 即 TLMM_DalTlmm_GpioIn(bstlmmhp, gpiocfg, pval)return TLMM_GpioIn(((DalTlmmHandle *)h)->pClientCtxt, gpio_config, value);DALTLMM.c (core\systemdrivers\tlmm\src)DALResult  TLMM_GpioIn(TLMMClientCtxt* pCtxt,DALGpioSignalType eGpioConfig,DALGpioValueType*  eValue)bHalRetVal = HAL_tlmm_ReadGpio(eGpioConfig);HALtlmm.c (core\systemdrivers\tlmm\hw\v2)---- HAL层boolean HAL_tlmm_ReadGpio( uint32 nWhichConfig ) nWhichGpio = (uint32)HAL_GPIO_NUMBER(nWhichConfig);---- 即 (((config)&0x3FF0)>>4) 得到 gpionumber 的值为 1HWIO_TLMM_GPIO_IN_OUTn_INMI(tHALTLMMInit.nBaseAddress, nWhichGpio, 0x1)---- 即 HWIO_TLMM_GPIO_IN_OUTn_INMI(tHALTLMMInit.nBaseAddress,1,1)#define HWIO_TLMM_GPIO_IN_OUTn_INMI(base,n,mask)    \        in_dword_masked(HWIO_TLMM_GPIO_IN_OUTn_ADDR(base,n), mask)#define HWIO_TLMM_GPIO_IN_OUTn_ADDR(base,n)    ((base) + 0x00000004 + 0x1000 * (n))---- 即 0x1000 0000+ 0x00000004 + 0x1000 = 0x1000 1004#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask))#define __inpdw(port)       (*((volatile uint32 *) (port)))---- 即从 0x1000 1004地址里读到值*************************************************_global boolean bsgpiowrite(DALGpioSignalType gpio,const DALGpioValueType val)---- 写 gpio dal_output = DalTlmm_GpioOut(bstlmmhp, gpio, val);static __inline DALResult DalTlmm_GpioOut(...)...   return ((DalTlmmHandle *)_h)->pVtbl->GpioOut( _h, gpio_config, value);----对应 TLMM_DalTlmm_GpioOut************** 假设 gpio=1    _global DALGpioSignalType bsgpiocfgasinput(uint16 gpio,DALGpioPullType type)----设置 goio 为输入DAL_GPIO_CFG(gpio, 0, DAL_GPIO_INPUT, type, DAL_GPIO_2MA);bsgpiocfg(gpio_config);_global void bsgpiocfg(  DALGpioSignalType gpio)----------------------------- 可以重点分析一下这个函数if (bstlmmhp == NULL)dal_attach = DAL_DeviceAttach(DALDEVICEID_TLMM, &bstlmmhp);---- Create a TLMM handleDalDevice_Open(bstlmmhp, DAL_OPEN_SHARED);DALSYS_BusyWait(30);    DalTlmm_ConfigGpio(bstlmmhp, gpio, DAL_TLMM_GPIO_ENABLE);---- 对应 HAL 层的 TLMM_DalTlmm_ConfigGpioTLMM_DalTlmm_ConfigGpio( DalDeviceHandle * h, DALGpioSignalType gpio_config, DALGpioEnableType enable) TLMM_ConfigGpio(((DalTlmmHandle *)h)->pClientCtxt, gpio_config, enable);DALResult TLMM_ConfigGpio(TLMMClientCtxt* pCtxt,DALGpioSignalType eGpioConfig,DALGpioEnableType eEnable)TLMM_ConfigGpioInternal(pCtxt, eGpioConfig, eEnable, NULL)static DALResult TLMM_ConfigGpioInternal(TLMMClientCtxt* pCtxt,DALGpioSignalType eGpioConfig,DALGpioEnableType eEnable,DALGpioIdType nGpioId)TLMM_ConfigGpioGroupInternal(pCtxt, eEnable, &eGpioConfig, 1, nGpioId)static DALResult TLMM_ConfigGpioGroupInternal(TLMMClientCtxt* pCtxt,DALGpioEnableType eEnable,DALGpioSignalType* eGpioGroup,uint32 nSize,DALGpioIdType nGpioId)HAL_tlmm_ConfigGpio(eGpioGroup[nIdx])void HAL_tlmm_ConfigGpio( uint32 nWhichConfig )HAL_tlmm_WriteGpio(...)---- 写输出的值HAL_tlmm_WriteConfig(nWhichGpio, (uint32)HAL_TLMM_GPIO_CONFIG_MASK(nWhichConfig));#define HAL_TLMM_GPIO_CONFIG_MASK(cfg)   \    ((HAL_PULL_VAL(cfg)   << 0x0) | \     (HAL_FUNC_VAL(cfg)   << 0x2) | \     (HAL_DRVSTR_VAL(cfg) << 0x6) | \     (HAL_DIR_VAL(cfg)    << 0x9) )0|0|00 00|00 00|00  dir drive funcpull void HAL_tlmm_WriteConfig( uint32 nGpioNumber, uint32 nConfig ) HWIO_TLMM_GPIO_CFGn_OUTI(tHALTLMMInit.nBaseAddress, nGpioNumber, nConfig); #define HWIO_TLMM_GPIO_CFGn_OUTI(base,n,val)    out_dword(HWIO_TLMM_GPIO_CFGn_ADDR(base,n),val)    ---- 上面有分析 即 out_dword(0x1000 1000 ,val)#define out_dword(addr, val)        __outpdw(addr,val) ---- 即往 0x1000 1000 写入 val#define __outpdw(port, val) (*((volatile uint32 *) (port)) = ((uint32) (val))) **************Bsio.c (sierra\bs\src)_global boolean bsgpioconfigget(DALGpioSignalType gpio,DALGpioSignalType * gpio_configp)----根据 gpionum 得到 gpio 配置DalTlmm_GetCurrentConfig(bstlmmhp, gpio, gpio_configp);DDITlmm.h (core\api\systemdrivers)static __inline DALResult DalTlmm_GetCurrentConfig(  DalDeviceHandle  *_h,   uint32           gpio_number,   DALGpioSignalType *gpio_config)if(DALISREMOTEHANDLE(_h))---- ??????   {      DalRemoteHandle *hRemote = (DalRemoteHandle *)DALPREPREMOTEHANDLE(_h);      return hRemote->pVtbl->FCN_2(DALVTBLIDX(((DalTlmmHandle *)_h)->pVtbl, GetCurrentConfig ), _h, gpio_number, (uint32*)gpio_config);   }   return ((DalTlmmHandle *)_h)->pVtbl->GetCurrentConfig( _h, gpio_number, gpio_config);DALTLMM.c (core\systemdrivers\tlmm\src)---- 假设在这??DALResult TLMM_GetCurrentConfig(  TLMMClientCtxt*    pCtxt,  uint32             nGpioNumber,  DALGpioSignalType* eGpioConfig)HAL_tlmm_GetConfig(nGpioNumber, &tTempCurrent);*eGpioConfig = DALTLMMState_StructToMacro(nGpioNumber, &tTempCurrent);**************./core/systemdrivers/tlmm/config/mdm9x45/TLMMChipset.xmlTLMM_DeviceInitTLMM_InitPlatformIO          pszPlatformIO = "TLMMPlatformIO_MTPCDP";static void TLMM_InitInterface(TLMMClientCtxt* pclientCtxt)    static const DalTlmm vtbl = {       {TLMM_DalTlmm_Init,} ,...}static DALResult TLMM_DalTlmm_Init(DalDeviceHandle *h)   return TLMM_DeviceInit(h->pClientCtxt);DALResult TLMM_DeviceInit(TLMMClientCtxt *pCtxt)DALSYS_SyncCreate(DALSYS_SYNC_ATTR_RESOURCE,&(pCtxt->pDevCtxt->hTlmmSync),&(pCtxt->pDevCtxt->hTlmmSyncObj))--- Initialize the synchronizationDALSYS_SyncEnter(pCtxt->pDevCtxt->hTlmmSync);---Ensure synchronization for critical initialization parametersDALSYS_GetDALPropertyHandle(pCtxt->pDevCtxt->DevId, pCtxt->pDevCtxt->hProp);---retrieve a handle to the TLMM properties fileDALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_total_gpio", 0, &tPropVar );--- 从 TLMMChipset.xml 中得到 tlmm_total_gpio =100DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_base", 0, &tPropVar );--- 得到 tlmm_base = TLMM_BASE_PHYS 为 0x01000000TLMM_InitPlatformIO(pCtxt);-------------------------------DAL_DeviceAttach(DALDEVICEID_HWIO, &hHWIODevice);--- Get a virtual or physical base depending on the memory mappingDalHWIO_MapRegionByAddress(hHWIODevice,(uint8 *)tPropVar.Val.dwVal,(uint8 **)&tHALInit.nBaseAddress);DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_offset", 0, &tPropVar );--- 得到 tlmm_offset = 0DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_ports", 0, &tPropVar );--- 得到 tlmm_ports =tlmm_port_cfg  -------------HAL_tlmm_Init(&tHALInit);--- Initialize the HAL interface.void TLMM_InitPlatformIO(TLMMClientCtxt *pCtxt)DalPlatformInfo_GetPlatformInfo(hPlatformInfo, &PlatformInfo);--- 得到平台信息, MTPCDP, MTP_FUSION, MTPCDPT2FUSION 中一个DALSYS_GetDALPropertyHandleStr(pszPlatformIO, pCtxt->pDevCtxt->hPlatIO);--- 从对应的 xml 文件里得到特殊GPIO配置信息


0 0
原创粉丝点击