居然快一年没有更新博客了,近段时间看了下以前的一些笔记,发现做过的项目,学习的知识都忘了差不多,其实还是应该抽点时间出来记录下。
当然先列出参考文章:
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
echo "c" > /proc/sysrq-trigger
根据 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: 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.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配置信息