天天看點

mdm9x07的GPIO相關筆記

居然快一年沒有更新部落格了,近段時間看了下以前的一些筆記,發現做過的項目,學習的知識都忘了差不多,其實還是應該抽點時間出來記錄下。

當然先列出參考文章:

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 long		flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED	0					//GPIO 申請的标志,已申請的話該标志是1,否則是0
#define FLAG_IS_OUT	1
#define FLAG_EXPORT	2	/* protected by sysfs_lock */
#define FLAG_SYSFS	3	/* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL	4	/* trigger on falling edge */
#define FLAG_TRIG_RISE	5	/* trigger on rising edge */
#define FLAG_ACTIVE_LOW	6	/* value has active low */
#define FLAG_OPEN_DRAIN	7	/* 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_SHIFT	16	/* 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);								//請求gpio
	void		(*free)(struct gpio_chip *chip,unsigned offset);								//釋放gpio
	int			(*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為輸出,并設定為value
	int			(*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);
	int			base;																			// 這個gpio控制器的gpio開始編号
	u16			ngpio;																			//這個gpio控制器說控制的gpio數
	struct gpio_desc	*desc;
	const char		*const *names;
	bool			can_sleep;
	bool			irq_not_threaded;
	bool			exported;

#ifdef CONFIG_GPIOLIB_IRQCHIP
	struct irq_chip		*irqchip;
	struct irq_domain	*irqdomain;
	unsigned int		irq_base;
	irq_flow_handler_t	irq_handler;
	unsigned int		irq_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_PINCTRL
	struct list_head pin_ranges;
#endif
}
           

開始一些有用的指令了

cat /sys/kernel/debug/gpio
           

這個指令可以得到全部GPIO的狀态

具體代碼分析如下:

gpiolib.c
static 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-79
	dev = chip->dev;
	seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",dev_name(dev));						--- 即 platform/1000000.pinctrl
	seq_printf(s, ", %s", chip->label);																	--- 即 , 1000000.pinctrl
	seq_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  1
	seq_printf(s, " %dmA", msm_regval_to_drive(drive));								---  2mA
	seq_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 GPIO1
echo 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_CONFIG
0x01000004+0x1000*n   GPIO_IN_OUT

GPIO16:0x1010000

GPIO36:0x1024000
GPIO37:0x1025000

寫寄存器
/ # devmem 0x1024000 w 0x201
/dev/mem opened.
Memory mapped at address 0xb6f4b000.
Value at address 0x1024000 (0xb6f4b000): 0x207
Written 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);						--- 1
	
1:
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 = 0
	status = gpiod_export(desc, true);		  --- 1.2

	
1.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.1
					MKDEV(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: [email protected] {
		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.c
int 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)													--- 2
	
1:
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.c
int 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_SEL
	tGpio->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_EN
	tGpio->nPull =  ((nTempConfig &  HWIO_TLMM_GPIO_CFGn_GPIO_PULL_BMSK)>> HWIO_TLMM_GPIO_CFGn_GPIO_PULL_SHFT);		--- 即 (nTempConfig&0x3) >>0,0x3= 0011 [1:0] ,為 GPIO_PULL
	tGpio->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 | 0000
				drive 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 DALResult
DalTlmm_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 的值為 1
	HWIO_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 handle
	DalDevice_Open(bstlmmhp, DAL_OPEN_SHARED);
	DALSYS_BusyWait(30);
    DalTlmm_ConfigGpio(bstlmmhp, gpio, DAL_TLMM_GPIO_ENABLE);		---- 對應 HAL 層的 TLMM_DalTlmm_ConfigGpio

TLMM_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 func	pull
 
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.xml

TLMM_DeviceInit
TLMM_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 synchronization
	DALSYS_SyncEnter(pCtxt->pDevCtxt->hTlmmSync);										---Ensure synchronization for critical initialization parameters
	DALSYS_GetDALPropertyHandle(pCtxt->pDevCtxt->DevId, pCtxt->pDevCtxt->hProp);		---retrieve a handle to the TLMM properties file
	DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_total_gpio", 0, &tPropVar );	--- 從 TLMMChipset.xml 中得到 tlmm_total_gpio =100
	DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_base", 0, &tPropVar );		--- 得到 tlmm_base = TLMM_BASE_PHYS 為 0x01000000
	TLMM_InitPlatformIO(pCtxt);			-------------------------------
	DAL_DeviceAttach(DALDEVICEID_HWIO, &hHWIODevice);									--- Get a virtual or physical base depending on the memory mapping
	DalHWIO_MapRegionByAddress(hHWIODevice,(uint8 *)tPropVar.Val.dwVal,(uint8 **)&tHALInit.nBaseAddress);
	DALSYS_GetPropertyValue( pCtxt->pDevCtxt->hProp, "tlmm_offset", 0, &tPropVar );		--- 得到 tlmm_offset = 0
	DALSYS_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配置資訊
           

繼續閱讀