static int s2mu003_mfd_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int ret = 0; u8 data = 0; struct device_node *of_node = i2c->dev.of_node; s2mu003_mfd_chip_t *chip; s2mu003_mfd_platform_data_t *pdata = i2c->dev.platform_data; pr_info("%s : S2MU003 MFD Driver start probe\n", __func__); if (of_node) { pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(&i2c->dev, "Failed to allocate memory\n"); ret = -ENOMEM; goto err_dt_nomem; } ret = s2mu003mfd_parse_dt(&i2c->dev, pdata); if (ret < 0) goto err_parse_dt; } else { pdata = i2c->dev.platform_data; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { dev_err(&i2c->dev, "Memory is not enough.\n"); ret = -ENOMEM; goto err_mfd_nomem; } chip->dev = &i2c->dev; ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); if (!ret) { ret = i2c_get_functionality(i2c->adapter); dev_err(chip->dev, "I2C functionality is not supported.\n"); ret = -ENOSYS; goto err_i2cfunc_not_support; } chip->i2c_client = i2c; chip->pdata = pdata; /* if board-init had already assigned irq_base (>=0) , no need to allocate it; assign -1 to let this driver allocate resource by itself*/ if (pdata->irq_base < 0) pdata->irq_base = irq_alloc_descs(-1, 0, S2MU003_IRQS_NR, 0); if (pdata->irq_base < 0) { pr_err("%s:%s irq_alloc_descs Fail! ret(%d)\n", "s2mu003-mfd", __func__, pdata->irq_base); ret = -EINVAL; goto irq_base_err; } else { chip->irq_base = pdata->irq_base; pr_info("%s:%s irq_base = %d\n", "s2mu003-mfd", __func__, chip->irq_base); irq_domain_add_legacy(of_node, S2MU003_IRQS_NR, chip->irq_base, 0, &irq_domain_simple_ops, NULL); } i2c_set_clientdata(i2c, chip); mutex_init(&chip->io_lock); wake_lock_init(&(chip->irq_wake_lock), WAKE_LOCK_SUSPEND, "s2mu003mfd_wakelock"); /* To disable MRST function should be finished before set any reg init-value*/ data = s2mu003_reg_read(i2c, 0x47); pr_info("%s : Manual Reset Data = 0x%x", __func__, data); s2mu003_clr_bits(i2c, 0x47, 1<<3); /*Disable Manual Reset*/ ret = s2mu003_init_irq(chip); if (ret < 0) { dev_err(chip->dev, "Error : can't initialize S2MU003 MFD irq\n"); goto err_init_irq; } #ifdef CONFIG_REGULATOR_S2MU003 ret = mfd_add_devices(chip->dev, 0, &s2mu003_regulator_devs[0], ARRAY_SIZE(s2mu003_regulator_devs), NULL, chip->irq_base, NULL); if (ret < 0) { dev_err(chip->dev, "Error : can't add regulator\n"); goto err_add_regulator_devs; } #endif /*CONFIG_REGULATOR_S2MU003*/ #ifdef CONFIG_LEDS_S2MU003 ret = mfd_add_devices(chip->dev, 0, &s2mu003_fled_devs[0], ARRAY_SIZE(s2mu003_fled_devs), NULL, chip->irq_base, NULL); if (ret < 0) { dev_err(chip->dev, "Failed : add FlashLED devices"); goto err_add_fled_devs; } #endif /*CONFIG_LEDS_S2MU003*/ #ifdef CONFIG_CHARGER_S2MU003 ret = mfd_add_devices(chip->dev, 0, &s2mu003_charger_devs[0], ARRAY_SIZE(s2mu003_charger_devs), NULL, chip->irq_base, NULL); if (ret < 0) { dev_err(chip->dev, "Failed : add charger devices\n"); goto err_add_chg_devs; } #endif /*CONFIG_CHARGER_S2MU003*/ device_init_wakeup(chip->dev, 1); enable_irq_wake(chip->irq); pr_info("%s : S2MU003 MFD Driver Fin probe\n", __func__); return ret; #ifdef CONFIG_CHARGER_S2MU003 err_add_chg_devs: #endif /*CONFIG_CHARGER_S2MU003*/ #ifdef CONFIG_LEDS_S2MU003 err_add_fled_devs: #endif /*CONFIG_LEDS_S2MU003*/ mfd_remove_devices(chip->dev); #ifdef CONFIG_REGULATOR_S2MU003 err_add_regulator_devs: #endif /*CONFIG_REGULATOR_S2MU003*/ err_init_irq: wake_lock_destroy(&(chip->irq_wake_lock)); mutex_destroy(&chip->io_lock); irq_base_err: err_i2cfunc_not_support: kfree(chip); err_mfd_nomem: if(pdata) kfree(pdata); err_parse_dt: err_dt_nomem: return ret; }
static int ta_notification(struct notifier_block *nb, unsigned long action, void *data) { muic_attached_dev_t attached_dev = *(muic_attached_dev_t *)data; u8 temp; int ret; struct s2mu003_led_data *led_data = container_of(nb, struct s2mu003_led_data, batt_nb); switch (action) { case MUIC_NOTIFY_CMD_DETACH: case MUIC_NOTIFY_CMD_LOGICALLY_DETACH: pr_info("%s : DETACH\n", __func__); if (!led_data->attach_ta) goto err; pr_info("%s : TA DETACH\n", __func__); ret = s2mu003_assign_bits(led_data->i2c, S2MU003_FLED_CTRL1, 0x80, 0x00); if (ret < 0) goto err; temp = s2mu003_reg_read(led_data->i2c, S2MU003_FLED_CH1_CTRL4); if ((temp & 0x0C) == 0x0C) { ret = s2mu003_assign_bits(led_data->i2c, S2MU003_FLED_CH1_CTRL4, S2MU003_TORCH_ENABLE_MASK, S2MU003_FLASH_TORCH_OFF); pr_info("%s : LED OFF\n", __func__); if (ret < 0) goto err; ret = s2mu003_assign_bits(led_data->i2c, S2MU003_FLED_CH1_CTRL4, S2MU003_TORCH_ENABLE_MASK, S2MU003_TORCH_ON_I2C); pr_info("%s : LED ON\n", __func__); if (ret < 0) goto err; } break; case MUIC_NOTIFY_CMD_ATTACH: case MUIC_NOTIFY_CMD_LOGICALLY_ATTACH: pr_info("%s : ATTACH", __func__); led_data->attach_ta = 0; attach_cable_check(attached_dev, &led_data->attach_ta); if (led_data->attach_ta) { ret = s2mu003_assign_bits(led_data->i2c, S2MU003_FLED_CTRL1, 0x80, 0x80); pr_info("%s : TA ATTACH\n", __func__); if (ret < 0) goto err; } return 0; default: goto err; break; } pr_info("%s : complete TA detached\n", __func__); return 0; err: pr_err("%s : abandond access %d\n", __func__, led_data->attach_ta); return 0; }