这个regulator 比较复杂点,主要调节是通过I2C,先看下sys目录:
sys/devices/platform/omap/omap_i2c.1/i2c-1
1-0048
1-0049
twl4030_gpio
twl4030_pwrbutton
twl4030-audio
1-004a
twl4030_keypad
1-004b --->regulator
twl_rtc
twl_reg.2 VIO
twl_reg.6 VMMC1
twl_reg.3 VDAC
twl_reg.10 VAUX2_4030(only 4030)
twl_reg.5 VPLL2
twl_reg.8 VSIM
twl_reg.12 VAUX3
1.platform device register
omap3_evm_i2c_init
=> omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
注册i2c 总线, omap3evm_i2c_boardinfo 为挂在总线上的多个slave的info
=> i2c_register_board_info (带client dev的)
=> omap_i2c_add_bus(bus_id) devname = "omap_i2c"
=> omap_device_build (这是1个hwmod 设备),实际最后也是注册platform device
(sys 目录如上/sys/devices/platform/omap/omap_i2c.1/)
之所以要omap_device_build ,而不是直接platform_device_register,
是要满足omap复杂的PCRM的L4,L3层的东西
=> platform device 被注册,如果总线已经注册驱动,驱动就去probe
2. platform driver register
platform_driver_register(&omap_i2c_driver);
static struct platform_driver omap_i2c_driver = {
.probe = omap_i2c_probe,
.remove = omap_i2c_remove,
.driver = {
.name = "omap_i2c",
.owner = THIS_MODULE,
},
};
开始probe
omap_i2c_probe (I2C_omap.c)
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
=> res = device_register(&adap->dev); (注册adaptor device)
(sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1)
=>i2c_add_numbered_adapter(adap);
=> i2c_register_adapter(adap);
=>i2c_scan_static_board_info(adap);
scan __i2c_board_list
=>i2c_new_device(adapter,&devinfo->board_info)
(I2C bus client device register )
client->dev.platform_data = info->platform_data; (就是omap3evm_twldata)
client->addr = info.add 就是0x48
strlcpy(client->name, info->type, sizeof(client->name));
client->name 如下omap3evm_i2c_boardinfo
= twl4030 (i2c bus match 时会比对)
......
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
dev_set_name(&client->dev, "%d-%04x", adap-nr, client->addr)
=> device_register(&client->dev);
(sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0048)
对于twl4030设备的i2c board info如下
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
/*#define I2C_BOARD_INFO(dev_type, dev_addr)
.type = twl4030, .addr = 0x48 第1个client 地址
*/
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &omap3evm_twldata,
},
};
上面device_register "1-0048"这个device ,进入
/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0048
其中包含的driver 进入该driver目录,其实他是个link
指向:/sys/bus/i2c/drivers/twl
dirver 名称叫twl,这个就是client driver!!!
在(twl-core.c)
static struct i2c_driver twl_driver = {
.driver.name = DRIVER_NAME, =>"twl"
.id_table = twl_ids,
.probe = twl_probe,
.remove = twl_remove,
};
twl_init
=> i2c_add_driver(&twl_driver);
=> i2c_register_driver(THIS_MODULE, driver);
(I2C bus driver register )
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices. */
res = driver_register(&driver->driver);
I2C总线上引起probe ,(关于总线的设备attach过程,可以跟下(bus_add_driver)了解
大概过程就是 driver_attach=> __driver_attach(bustype)
=>driver_match_device(bus->match)
=> driver_probe_device(bus->probe)
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
下面继续跟bus->probe(i2c_device_probe),
really_probe(dev,driver) => driver->probe
driver 就是twl_driver ,driver->probe 就是twl_probe
twl_probe
struct twl4030_platform_data *pdata = client->dev.platform_data;
就是omap3evm_twldata
TWL_NUM_SLAVES 有4个第一个0x48已经生成
twl_client twl_modules[0] = 等于0x48 client
=> i2c_new_dummy( ,0x48++)
这样就生成了剩余的3个client,
(sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0049,1-004a,1-004b)
=> add_children(omap3evm_twldata,TWL4030_VAUX2)
=> 目前只关心 regulator
主要regulator 如下:
add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
child = add_regulator(TWL4030_REG_VIO, pdata->vio);
child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
child = add_regulator((features & TWL4030_VAUX2)
? TWL4030_REG_VAUX2_4030: TWL4030_REG_VAUX2,pdata->vaux2);
child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
child = add_regulator(TWL4030_REG_VUSB1V5, pdata->vusb1v5);
child = add_regulator(TWL4030_REG_VUSB1V8, pdata->vusb1v8);
child = add_regulator(TWL4030_REG_VUSB3V1, pdata->vusb3v1);
=>add_regulator_linked(int num, struct regulator_init_data *pdata,
struct regulator_consumer_supply *consumers, unsigned num_consumers)
=> 根据static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1]
查到subchipid 是3,就是0x4b ,查看下目录
/sys/devices/platform/omap/omap_i2c.1/i2c-1/1——004b
的确regulator 都在这里
=> add_numbered_child(sub_chip_id=3, "twl_reg", num=TWL4030_REG_VMMC1,
pdata, sizeof(*pdata), false, 0, 0);
=> 下面看下vmmc1的 add add_regulator_linked过程
=> platform_device_alloc(name=twl_reg, num=TWL4030_REG_VMMC1(6));
platform_device_add_data, tel_reg.6的platformdata=pdata->vmmc1
就是下面的omap3evm_vmmc1
static struct regulator_consumer_supply omap3evm_vmmc1_supply = {
.supply = "vmmc",
};
static struct regulator_consumer_supply omap3evm_vsim_supply = {
.supply = "vmmc_aux",
};
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data omap3evm_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &omap3evm_vmmc1_supply,
};
=> 最后platform_device_add(pdev)
注册regulator vmmc1的platform device
于是/sys/devices/platform/omap/omap_i2c.1/i2c-1/1_004b/twl_reg.6生成
其他以次类推,根据omap3evm_twldata实际传入regulator 相关 有下面几组:
static struct twl4030_platform_data omap3evm_twldata = {
.vdac = &omap3_evm_vdac,
.vpll2 = &omap3_evm_vpll2,
.vaux2 = &omap3evm_vaux2,
.vio = &omap3_evm_vio,
.vaux3 = &omap3evm_vaux3,
};
另外两组,直接赋值:
omap3evm_twldata.vmmc1 = &omap3evm_vmmc1;
omap3evm_twldata.vsim = &omap3evm_vsim;
共7组
查看目录/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-004b
twl_reg.2 VIO
twl_reg.6 VMMC1
twl_reg.3 VDAC
twl_reg.10 VAUX2_4030(only 4030)
twl_reg.5 VPLL2
twl_reg.8 VSIM
twl_reg.12 VAUX3
实际也是如此
经过上面过程所有twl regulator platform device 已经注册完成
接下来就是twl_reg driver 了
twl-regulator.c 中 定义twl regulator driver 结构如下:
static struct platform_driver twlreg_driver = {
.probe = twlreg_probe,
.remove = __devexit_p(twlreg_remove),
/* NOTE: short name, to work around driver model truncation of
* "twl_regulator.12" (and friends) to "twl_regulator.1".
*/
.driver.name = "twl_reg",
.driver.owner = THIS_MODULE,
};
platform_driver_register(&twlreg_driver); 执行后,引发platform bus probe
经过attach,match后执行到
twlreg_probe
=> 根据pdev.id(就是上面twl_reg.x)到 struct twlreg_info
twl_regs查找匹配twl_info
然后根据dev 的platform_data活动regulator init data
比如 vmmc1 twl_info为:
/*
.base = 0x27, (+0x5b PM_RECEIVER start addr ) 0x82
VMMC1_DEV_GRP RW 8 0x00 0x27 0x82 P187
.id = 5,
.table_len = ARRAY_SIZE(VMMC1_VSEL_table), 1850, 2850, 3000, 3150,
.table = VMMC1_VSEL_table,
.delay = 100,
.remap = 0x8,
.desc = { regulator_desc ,主要是regulator ops函数组设置
.name = "VMMC1",
.id = TWL4030_REG_VMMC1,
.n_voltages = ARRAY_SIZE(VMMC1_VSEL_table),
.ops = &twl4030ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
}*/
接下来对传入的 regulator init data中constraint进行调整
然后regulator_register(&info->desc, &pdev->dev, initdata, info);
向regulator core注册regulator,这样以后可以通过regulator core中
接口对twl_reg 进行操作,实际操作是twl4030ldo_ops 中对应function
最后
twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,info->remap);
return twl_i2c_write_u8(slavesugp=TWL_MODULE_PM_RECEIVER=0x15
, value=info.remap=0x8, info->base + offset=0x27+2);
TWL_MODULE_PM_RECEIVER 可以到twl_map中查pm receiver base addr!
表示对client 0x4b addr ,VMMC1_REMAP (RW 8 0x08 0x29 0x84)register
写入0x8 (如 P199 描述)
When VMMC1 device is either in SLEEP or OFF mode allows to
set the resource in Active or OFF/SLEEP (VRRTC
domain)
接下来主要是regulator 的操作函数,和omap pmic 的PM相关register
对于omap pmic PM 部分
1. PM_RECEIVER 对某个power resource 操作
对应每个regulator 主要有DEV_GRP,TYPE,REMAP,DEDICATE
比如VMMC1 (P187)
VMMC1_DEV_GRP RW 8 0x00 0x27 0x82
VMMC1_TYPE RW 8 0x00 0x28 0x83
VMMC1_REMAP RW 8 0x08 0x29 0x84
VMMC1_DEDICATED RW 8 0x02 0x2A 0x85
2. PM_MASTER
对整个PMIC的操作,比如sequancer,reset等等
static struct regulator_ops twl4030ldo_ops = {
.list_voltage = twl4030ldo_list_voltage,
.set_voltage = twl4030ldo_set_voltage,
.get_voltage = twl4030ldo_get_voltage,
.enable = twlreg_enable,
.disable = twlreg_disable,
.is_enabled = twlreg_is_enabled,
.set_mode = twlreg_set_mode,
.get_status = twlreg_get_status,
};
1. twlreg_enable
主要操作就是设置DEV_GRP register
P1_GRP_4030(bit(5)) 001: Associated with P1 device group
表示关联到MPU group,这样就enable了
2. twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
操作 DEDICATE register
对于VMMC1
static const u16 VMMC1_VSEL_table[] = {
1850, 2850, 3000, 3150,
};
在电压表中查找,4个电压中满足>=min_uV 并且<=max_uV
并设置VMMC1_DEDICATED,中VSEL(0-3) 进行选择
omap_hsmmc_switch_opcond=>
在omap_hsmmc_1_set_power=>
=>mmc_regulator_set_ocr=>
regulator_set_voltage(supply, min_uV, max_uV);
设置卡电压
3. twlreg_set_mode
就是发power bus message
首先生成sigular message,根据 REGULATOR_MODE_NORMAL,or STANDBY
消息格式为 P252:
DEV_GR[2:0] Power Providers (PP)
Reset and Control (PC)
Power Reference (PR)
MT - sigular
RES_ID[7:0] P246
RES_STATE[3:0] P243 都有解释
然后读该regulator(power source) 是否关联P1,2,3
最后写PMB MSB, LSB ,完成mode转换
* I2c 操作到pmic reg 定位:
1. PM MASTER register:
int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
mod_no -- 定义在 twl.h
比如:
#define TWL4030_MODULE_PM_MASTER 0x14
根据twl4030_map[mod_no],可以获得sid(slave id)
再根据sid 从 twl_modules 获得哪个twl_client(他包含slave addr)
reg -- 定义为offset,通过mod_no查base reg addr ,然后加上reg
twl_map[mod_no].base + reg;
比如PM Receiver base =>
#define TWL4030_BASEADD_PM_MASTER 0x0036
而 Power bus msg reg offset =>
#define TWL4030_PM_MASTER_PB_WORD_MSB 0x15
0x36+0x15 =0x4B 就是PB_WORD_MSB reg addr
2. PM RECEIVER register:
int twlreg_write(struct twlreg_info *info, unsigned slave_subgp,
unsigned offset, u8 value)
下面这个和上面类似
但多了twlreg_info ,用来确定某twl regulator(power source)的base addr
twlreg_info 定义在
static struct twlreg_info twl_regs[] (twl_regulator.c)
全局数组中
offset就是
#define VREG_GRP 0
/* TWL4030 register offsets */
#define VREG_TYPE 1
#define VREG_REMAP 2
#define VREG_DEDICATED 3 /* LDO control */
* sysfs attrib:
add_regulator_attributes (regulator core.c) ,比如
/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-004b/twl_reg.15/regulator/regulator.7
的 microvolts 查看当前电压