#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../axp-core.h" #include "../axp-charger.h" #include "../axp-regulator.h" #include "pmu1736.h" #include "pmu1736-regu.h" static struct axp_dev *pmu1736_pm_power; struct axp_config_info pmu1736_config; struct wakeup_source *pmu1736_ws; static int pmu1736_pmu_num; static const struct axp_compatible_name_mapping pmu1736_cn_mapping[] = { { .device_name = "pmu1736", .mfd_name = { .powerkey_name = "pmu1736-powerkey", .regulator_name = "pmu1736-regulator", .gpio_name = "pmu1736-gpio", }, }, }; static struct axp_regmap_irq_chip pmu1736_regmap_irq_chip = { .name = "pmu1736_irq_chip", .status_base = PMU1736_INTSTS1, .enable_base = PMU1736_INTEN1, .num_regs = 3, }; static struct resource pmu1736_pek_resources[] = { {PMU1736_IRQ_PEKRE, PMU1736_IRQ_PEKRE, "PEK_DBR", IORESOURCE_IRQ,}, {PMU1736_IRQ_PEKFE, PMU1736_IRQ_PEKFE, "PEK_DBF", IORESOURCE_IRQ,}, }; static struct resource pmu1736_regulator_resources[] = { {PMU1736_IRQ_DC6UN, PMU1736_IRQ_DC6UN, "dc6 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC5UN, PMU1736_IRQ_DC5UN, "dc5 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC4UN, PMU1736_IRQ_DC4UN, "dc4 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC3UN, PMU1736_IRQ_DC3UN, "dc3 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC2UN, PMU1736_IRQ_DC2UN, "dc2 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC1UN, PMU1736_IRQ_DC1UN, "dc1 under 85", IORESOURCE_IRQ,}, {PMU1736_IRQ_LOWN1, PMU1736_IRQ_LOWN1, "low warning1", IORESOURCE_IRQ,}, {PMU1736_IRQ_LOWN2, PMU1736_IRQ_LOWN2, "low warning2", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC3OV, PMU1736_IRQ_DC3OV, "dc3 over cur", IORESOURCE_IRQ,}, {PMU1736_IRQ_DC2OV, PMU1736_IRQ_DC2OV, "dc2 over cur", IORESOURCE_IRQ,}, }; static struct mfd_cell pmu1736_cells[] = { { .name = "pmu1736-powerkey", .num_resources = ARRAY_SIZE(pmu1736_pek_resources), .resources = pmu1736_pek_resources, }, { .name = "pmu1736-regulator", .num_resources = ARRAY_SIZE(pmu1736_regulator_resources), .resources = pmu1736_regulator_resources, }, { .name = "pmu1736-gpio", }, }; void pmu1736_power_off(void) { pr_info("[axp] send power-off command!\n"); axp_regmap_write(pmu1736_pm_power->regmap, PMU1736_PWR_DISABLE_DOWN, 0x80); } static int pmu1736_init_chip(struct axp_dev *pmu1736) { uint8_t chip_id; int err; err = axp_regmap_read(pmu1736->regmap, PMU1736_IC_TYPE, &chip_id); if (err) { pr_err("[%s] try to read chip id failed!\n", axp_name[pmu1736_pmu_num]); // return err; } if (((chip_id & 0xc0) == 0x40) && ((chip_id & 0x0f) == 0x04) ) { pr_info("[%s] chip id detect 0x%x !\n", axp_name[pmu1736_pmu_num], chip_id); } else { pr_info("[%s] chip id not detect 0x%x !\n", axp_name[pmu1736_pmu_num], chip_id); } /* enable dcdc2 dvm */ err = axp_regmap_update(pmu1736->regmap, PMU1736_DCDC_MODE_CTL1, 0x4, 0x4); if (err) { pr_err("[%s] enable dcdc2 dvm failed!\n", axp_name[pmu1736_pmu_num]); return err; } else { pr_info("[%s] enable dcdc2 dvm.\n", axp_name[pmu1736_pmu_num]); } /*init irq wakeup en*/ if (pmu1736_config.pmu_irq_wakeup) axp_regmap_set_bits(pmu1736->regmap, PMU1736_IRQ_PWROK_VOFF, 0x80); else axp_regmap_clr_bits(pmu1736->regmap, PMU1736_IRQ_PWROK_VOFF, 0x80); /*init pmu over temperature protection*/ if (pmu1736_config.pmu_hot_shutdown) axp_regmap_set_bits(pmu1736->regmap, PMU1736_PWR_DISABLE_DOWN, 0x02); else axp_regmap_clr_bits(pmu1736->regmap, PMU1736_PWR_DISABLE_DOWN, 0x02); return 0; } static void pmu1736_wakeup_event(void) { __pm_wakeup_event(pmu1736_ws, 0); } static s32 pmu1736_usb_det(void) { return 0; } static s32 pmu1736_usb_vbus_output(int high) { return 0; } static const char *pmu1736_get_pmu_name(void) { return axp_name[pmu1736_pmu_num]; } static struct axp_dev *pmu1736_get_pmu_dev(void) { return pmu1736_pm_power; } struct axp_platform_ops pmu1736_platform_ops = { .usb_det = pmu1736_usb_det, .usb_vbus_output = pmu1736_usb_vbus_output, .get_pmu_name = pmu1736_get_pmu_name, .get_pmu_dev = pmu1736_get_pmu_dev, }; static struct of_device_id pmu1736_match[] = { { .compatible = "pmu1736", }, {}, }; MODULE_DEVICE_TABLE(of, pmu1736_match); #ifdef CONFIG_AXP_TWI_USED static int pmu1736_probe(struct i2c_client *client, const struct i2c_device_id *id) #else static int pmu1736_probe(struct platform_device *pdev) #endif { int ret; struct axp_dev *pmu1736; struct device_node *node; struct device *device; #ifdef CONFIG_AXP_TWI_USED node = client->dev.of_node; device = &client->dev; #else node = pdev->dev.of_node; device = &pdev->dev; #endif pmu1736_pmu_num = axp_get_pmu_num(pmu1736_cn_mapping, ARRAY_SIZE(pmu1736_cn_mapping)); if (pmu1736_pmu_num < 0) { pr_err("%s: get pmu num failed\n", __func__); return pmu1736_pmu_num; } if (node) { /* get dt and sysconfig */ if (!of_device_is_available(node)) { pmu1736_config.pmu_used = 0; pr_err("%s: pmu_used = %u\n", __func__, pmu1736_config.pmu_used); return -EPERM; } else { pmu1736_config.pmu_used = 1; ret = axp_dt_parse(node, pmu1736_pmu_num, &pmu1736_config); if (ret) { pr_err("%s parse device tree err\n", __func__); return -EINVAL; } } } else { pr_err("pmu1736 device tree err!\n"); return -EBUSY; } pmu1736 = devm_kzalloc(device, sizeof(*pmu1736), GFP_KERNEL); if (!pmu1736) return -ENOMEM; pmu1736->dev = device; pmu1736->nr_cells = ARRAY_SIZE(pmu1736_cells); pmu1736->cells = pmu1736_cells; pmu1736->pmu_num = pmu1736_pmu_num; pmu1736->is_slave = pmu1736_config.pmu_as_slave; #ifdef CONFIG_AXP_TWI_USED pmu1736->irq = client->irq; #else pmu1736->irq = platform_get_irq(pdev, 0); #endif if (pmu1736->irq < 0) { pr_err("pmu1736 get irq error!\n"); return -EINVAL; } ret = axp_mfd_cell_name_init(pmu1736_cn_mapping, ARRAY_SIZE(pmu1736_cn_mapping), pmu1736->pmu_num, pmu1736->nr_cells, pmu1736->cells); if (ret) return ret; #ifdef CONFIG_AXP_TWI_USED pmu1736->regmap = axp_regmap_init_i2c(device); #else pmu1736->regmap = axp_regmap_init_arisc_rsb(device, 0x2d); #endif if (IS_ERR(pmu1736->regmap)) { ret = PTR_ERR(pmu1736->regmap); dev_err(device, "regmap init failed: %d\n", ret); return ret; } #ifdef CONFIG_AXP_TWI_USED i2c_set_clientdata(client, pmu1736); #else platform_set_drvdata(pdev, pmu1736); #endif ret = pmu1736_init_chip(pmu1736); if (ret) return ret; ret = axp_mfd_add_devices(pmu1736); if (ret) { dev_err(pmu1736->dev, "failed to add MFD devices: %d\n", ret); return ret; } #if 0 pmu1736->irq = gpio_to_irq(40); //i2s0 mclk pmu1736->irq_data = axp_irq_chip_register(pmu1736->regmap, pmu1736->irq, IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_TRIGGER_LOW | IRQF_ONESHOT, &pmu1736_regmap_irq_chip, NULL); #else if (pmu1736->is_slave) { pmu1736->irq_data = axp_irq_chip_register(pmu1736->regmap, pmu1736->irq, IRQF_SHARED | IRQF_NO_SUSPEND, &pmu1736_regmap_irq_chip, NULL); } else { pmu1736->irq_data = axp_irq_chip_register(pmu1736->regmap, pmu1736->irq, IRQF_SHARED | IRQF_NO_SUSPEND, &pmu1736_regmap_irq_chip, pmu1736_wakeup_event); } if (IS_ERR(pmu1736->irq_data)) { ret = PTR_ERR(pmu1736->irq_data); dev_err(device, "axp init irq failed: %d\n", ret); return ret; } #endif pmu1736_pm_power = pmu1736; if (!pmu1736->is_slave) { if (!pm_power_off) pm_power_off = pmu1736_power_off; } axp_platform_ops_set(pmu1736->pmu_num, &pmu1736_platform_ops); if (!pmu1736->is_slave) pmu1736_ws = wakeup_source_register("pmu1736_wakeup_source"); return 0; } #ifdef CONFIG_AXP_TWI_USED static int pmu1736_remove(struct i2c_client *client) #else static int pmu1736_remove(struct platform_device *pdev) #endif { #ifdef CONFIG_AXP_TWI_USED struct axp_dev *pmu1736 = i2c_get_clientdata(client); #else struct axp_dev *pmu1736 = platform_get_drvdata(pdev); #endif if (pmu1736 == pmu1736_pm_power) { pmu1736_pm_power = NULL; pm_power_off = NULL; } axp_mfd_remove_devices(pmu1736); axp_irq_chip_unregister(pmu1736->irq, pmu1736->irq_data); return 0; } static const struct i2c_device_id pmu1736_id_table[] = { { "pmu1736", 0 }, }; #ifdef CONFIG_AXP_TWI_USED static const unsigned short pmu1736_i2c_addr[] = { 0x6c, I2C_CLIENT_END, }; static int pmu1736_i2c_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; if (adapter->nr == 0) { strlcpy(info->type, "pmu1736", I2C_NAME_SIZE); return 0; } return -ENODEV; } #endif #ifdef CONFIG_AXP_TWI_USED static struct i2c_driver pmu1736_driver = { #else static struct platform_driver pmu1736_driver = { #endif .driver = { .name = "pmu1736", .owner = THIS_MODULE, .of_match_table = pmu1736_match, }, .probe = pmu1736_probe, .remove = pmu1736_remove, #ifdef CONFIG_AXP_TWI_USED .id_table = pmu1736_id_table, .address_list = pmu1736_i2c_addr, .detect = pmu1736_i2c_detect, #endif }; static int __init pmu1736_init(void) { int ret; #ifdef CONFIG_AXP_TWI_USED ret = i2c_add_driver(&pmu1736_driver); #else ret = platform_driver_register(&pmu1736_driver); #endif if (ret != 0) pr_err("Failed to register pmu1736 driver: %d\n", ret); return ret; } subsys_initcall(pmu1736_init); static void __exit pmu1736_exit(void) { #ifdef CONFIG_AXP_TWI_USED i2c_del_driver(&pmu1736_driver); #else platform_driver_unregister(&pmu1736_driver); #endif } module_exit(pmu1736_exit); MODULE_DESCRIPTION("PMIC Driver for PMU1736"); MODULE_AUTHOR("Qin "); MODULE_LICENSE("GPL");