nxe2100芯片是nxe2000的升级芯片,它提供5个DCDC,10个LDO,2个LDORTC。
High Efficiency Step-down DC/DC Converters
* DCDC1 -3 0.6V-3.5V Max 3000mA
* DCDC4-5 0.6V-3.5V Max 2000mA
* Soft-start circuit
●Low Drop Voltage Regulators
* LDO1 -4 with ECO 0.9V-3.5V Max 300mA
* LDO5-6 with ECO 0.6V-3.5V Max 300mA
* LDO7-10 0.9V-3.5V Max 200mA
* LDORTC1 1.7-3.5V Max 10mA (AlwaysOn, For coin battery)
* LDORTC2 0.9-3.5V Max 10mA (AlwaysOn)
NXE2100的驱动可以在NXE2000的驱动上修改:
linux配置中有以下配置包含了NXE2000:
(1)drivers/power下的kconfig:
config BATTERY_NXE2000(drivers/power/nxe2000-battery.c)。选择它同时会选择MFD_NXE2000(drivers/mfd/nxe2000.c和nxe2000-irq.c)和REGULATOR_NXE2000。
(2)drivers/mfd下的kconfig
config MFD_NXE2000。选择它同时会选择MFD_CORE
(4) drivers/regulator下的kconfig
config REGULATOR_NXE2000(drivers/regulator/nxe2000-regulator.c)。选择它同时会选择MFD_NXE2000
nxe2000是一个I2C设备,它的驱动挂载到I2C总线上:
static struct i2c_board_info __initdata nxe2000_i2c_boardinfo[] = { { I2C_BOARD_INFO("nxe2000", NXE2000_I2C_ADDR), .irq = CFG_GPIO_PMIC_INTR, .platform_data = &nxe2000_platform, }, };NXE2000.c是它的驱动,其中probe的实现如下:
static int nxe2000_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct nxe2000 *nxe2000; struct nxe2000_platform_data *pdata = client->dev.platform_data; int ret; nxe2000 = kzalloc(sizeof(struct nxe2000), GFP_KERNEL); if (nxe2000 == NULL) return -ENOMEM; nxe2000->client = client; nxe2000->dev = &client->dev; i2c_set_clientdata(client, nxe2000); mutex_init(&nxe2000->io_lock); nxe2000->bank_num = 0; /* For init PMIC_IRQ port */ // ret = pdata->init_port(client->irq); if (client->irq) { nxe2000->irq_base = pdata->irq_base; nxe2000->chip_irq = gpio_to_irq(client->irq); nxe2000->chip_irq_type = pdata->irq_type; ret = nxe2000_irq_init(nxe2000); if (ret) { dev_err(&client->dev, "IRQ init failed: %d\n", ret); goto err_irq_init; } } ret = nxe2000_add_subdevs(nxe2000, pdata); if (ret) { dev_err(&client->dev, "add devices failed: %d\n", ret); goto err_add_devs; } nxe2000_noe_init(nxe2000); nxe2000_gpio_init(nxe2000, pdata); nxe2000_debuginit(nxe2000); #ifdef CONFIG_NXE2000_WDG_TEST nxe2000_watchdog_init(nxe2000); #endif nxe2000_i2c_client = client; backup_pm_power_off = pm_power_off; pm_power_off = nxe2000_power_off; #if (NXE2000_PM_RESTART == 1) backup_pm_restart = arm_pm_restart; arm_pm_restart = nxe2000_restart; #endif return 0; err_add_devs: if (client->irq) nxe2000_irq_exit(nxe2000); err_irq_init: kfree(nxe2000); return ret; }nxe2000_add_subdevs函数的功能是添加子设备,子设备的定义在结构nxe2000_devs_dcdc中:
#define NXE2000_DEV_REG \ NXE2000_REG(DC1, dc1, 0), \ NXE2000_REG(DC2, dc2, 0), \ NXE2000_REG(DC3, dc3, 0), \ NXE2000_REG(DC4, dc4, 0), \ NXE2000_REG(DC5, dc5, 0), \ NXE2000_REG(LDO1, ldo1, 0), \ NXE2000_REG(LDO2, ldo2, 0), \ NXE2000_REG(LDO3, ldo3, 0), \ NXE2000_REG(LDO4, ldo4, 0), \ NXE2000_REG(LDO5, ldo5, 0), \ NXE2000_REG(LDO6, ldo6, 0), \ NXE2000_REG(LDO7, ldo7, 0), \ NXE2000_REG(LDO8, ldo8, 0), \ NXE2000_REG(LDO9, ldo9, 0), \ NXE2000_REG(LDO10, ldo10, 0), \ NXE2000_REG(LDORTC1, ldortc1, 0), \ NXE2000_REG(LDORTC2, ldortc2, 0) static struct nxe2000_subdev_info nxe2000_devs_dcdc[] = { NXE2000_DEV_REG, NXE2000_BATTERY_REG, NXE2000_PWRKEY_REG, #ifdef CONFIG_NXE2000_RTC NXE2000_RTC_REG, #endif };
struct nxe2000_subdev_info { int id; const char *name; void *platform_data; };nxe2000_add_subdevs函数为上面定义的数组中定义的项新建一个设备:
static int nxe2000_add_subdevs(struct nxe2000 *nxe2000, struct nxe2000_platform_data *pdata) { struct nxe2000_subdev_info *subdev; struct platform_device *pdev; int i, ret = 0; for (i = 0; i < pdata->num_subdevs; i++) { subdev = &pdata->subdevs[i]; pdev = platform_device_alloc(subdev->name, subdev->id); pdev->dev.parent = nxe2000->dev; pdev->dev.platform_data = subdev->platform_data; ret = platform_device_add(pdev); if (ret) goto failed; } return 0; failed: nxe2000_remove_subdevs(nxe2000); return ret; }其中,每个DCDC、LDO设备是一个nxe2000-regulator设备:
#define NXE2000_REG(_id, _name, _sname) \ { \ .id = NXE2000_ID_##_id, \ .name = "nxe2000-regulator", \ .platform_data = &pdata_##_name##_##_sname, \ }
在nxe2000-regulator.c中定义了这个设备。
static int __devinit nxe2000_regulator_probe(struct platform_device *pdev) { struct nxe2000_regulator *ri = NULL; struct regulator_dev *rdev; struct nxe2000_regulator_platform_data *tps_pdata; int id = pdev->id; int err; ri = find_regulator_info(id); if (ri == NULL) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); return -EINVAL; } tps_pdata = pdev->dev.platform_data; ri->dev = &pdev->dev; nxe2000_suspend_status = 0; err = nxe2000_cache_regulator_register(pdev->dev.parent, ri); if (err) { dev_err(&pdev->dev, "Fail in caching register\n"); return err; } err = nxe2000_regulator_preinit(pdev->dev.parent, ri, tps_pdata); if (err) { dev_err(&pdev->dev, "Fail in pre-initialisation\n"); return err; } rdev = regulator_register(&ri->desc, &pdev->dev, &tps_pdata->regulator, ri, NULL); if (IS_ERR_OR_NULL(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); return PTR_ERR(rdev); } platform_set_drvdata(pdev, rdev); return 0; }