居然快一年沒有更新部落格了,近段時間看了下以前的一些筆記,發現做過的項目,學習的知識都忘了差不多,其實還是應該抽點時間出來記錄下。
當然先列出參考文章:
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配置資訊