static int bcmpmu_spa_pb_probe(struct platform_device *pdev) { int ret = 0; struct bcmpmu_spa_pb *bcmpmu_spa_pb; struct bcmpmu59xxx *bcmpmu = dev_get_drvdata(pdev->dev.parent); struct bcmpmu59xxx_spa_pb_pdata *pdata; pdata = (struct bcmpmu59xxx_spa_pb_pdata *)pdev->dev.platform_data; pr_pb(INIT, "%s\n", __func__); BUG_ON(!(bcmpmu->flags & BCMPMU_SPA_EN) || !pdata); bcmpmu_spa_pb = kzalloc(sizeof(struct bcmpmu_spa_pb), GFP_KERNEL); if (bcmpmu_spa_pb == NULL) { dev_err(&pdev->dev, "failed to alloc mem: %d\n", ret); return -ENOMEM; } bcmpmu_info = bcmpmu; bcmpmu_spa_pb->bcmpmu = bcmpmu; bcmpmu->spa_pb_info = (void *)bcmpmu_spa_pb; mutex_init(&bcmpmu_spa_pb->lock); INIT_DELAYED_WORK(&bcmpmu_spa_pb->spa_work, bcmpmu_spa_pb_work); bcmpmu_spa_pb->chrgr.properties = bcmpmu_spa_pb_chrgr_props; bcmpmu_spa_pb->chrgr.num_properties = ARRAY_SIZE(bcmpmu_spa_pb_chrgr_props); bcmpmu_spa_pb->chrgr.get_property = bcmpmu_spa_pb_chrgr_get_property; bcmpmu_spa_pb->chrgr.set_property = bcmpmu_spa_pb_chrgr_set_property; bcmpmu_spa_pb->chrgr.name = pdata->chrgr_name; ret = power_supply_register(&pdev->dev, &bcmpmu_spa_pb->chrgr); if (ret) goto cghr_err; bcmpmu->register_irq(bcmpmu, PMU_IRQ_MBTEMPLOW, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); bcmpmu->register_irq(bcmpmu, PMU_IRQ_MBTEMPHIGH, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); bcmpmu->register_irq(bcmpmu, PMU_IRQ_CHGERRDIS, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); bcmpmu->register_irq(bcmpmu, PMU_IRQ_MBOV, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); bcmpmu->register_irq(bcmpmu, PMU_IRQ_MBOV_DIS, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); #if 0 /* Don't use PMU_IRQ_USBOV/PMU_IRQ_USBOV_DIS interrupt bacause PMU's USBOV threshold(6.6V/8V) can't meet SS spec(6.8V). So, SS use MUIC USBOV function(6.8V) instead of PMU USBOV*/ bcmpmu->register_irq(bcmpmu, PMU_IRQ_USBOV, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); bcmpmu->register_irq(bcmpmu, PMU_IRQ_USBOV_DIS, bcmpmu_spa_pb_isr, bcmpmu_spa_pb); #endif bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_MBTEMPLOW); bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_MBTEMPHIGH); bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_CHGERRDIS); bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_MBOV); bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_MBOV_DIS); #if 0 bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_USBOV); bcmpmu->unmask_irq(bcmpmu, PMU_IRQ_USBOV_DIS); #endif bcmpmu_spa_pb->nb_chgr_det.notifier_call = bcmpmu_spa_pb_event_hndlr; ret = bcmpmu_add_notifier(PMU_ACCY_EVT_OUT_CHRGR_TYPE, &bcmpmu_spa_pb->nb_chgr_det); if (ret) { pr_pb(ERROR, "%s, failed to register chrgr det notifier\n", __func__); goto err; } bcmpmu_spa_pb->nb_usbin.notifier_call = bcmpmu_spa_pb_event_hndlr; ret = bcmpmu_add_notifier(PMU_ACCY_EVT_OUT_USB_IN, &bcmpmu_spa_pb->nb_usbin); if (ret) { pr_pb(ERROR, "%s, failed to register chrgr det notifier\n", __func__); goto err; } #ifdef CONFIG_DEBUG_FS bcmpmu_spa_pb_dbg_init(bcmpmu_spa_pb); #endif return 0; err: bcmpmu_remove_notifier(PMU_ACCY_EVT_OUT_CHRGR_TYPE, &bcmpmu_spa_pb->nb_chgr_det); bcmpmu_remove_notifier(PMU_ACCY_EVT_OUT_USB_IN, &bcmpmu_spa_pb->nb_usbin); power_supply_unregister(&bcmpmu_spa_pb->chrgr); cghr_err: kfree(bcmpmu_spa_pb); return ret; }
static int __devinit bcmpmu_otg_xceiv_probe(struct platform_device *pdev) { int error = 0; struct bcmpmu_otg_xceiv_data *xceiv_data; struct bcmpmu *bcmpmu = pdev->dev.platform_data; dev_info(&pdev->dev, "Probing started...\n"); xceiv_data = kzalloc(sizeof(*xceiv_data), GFP_KERNEL); if (!xceiv_data) { dev_warn(&pdev->dev, "Memory allocation failed\n"); return -ENOMEM; } /* REVISIT: Currently there isn't a way to obtain * regulator string associated with USB. Hardcode for now */ xceiv_data->bcm_hsotg_regulator = regulator_get(NULL, "usbldo_uc"); if (IS_ERR(xceiv_data->bcm_hsotg_regulator)) { dev_warn(&pdev->dev, "Failed to get regulator handle\n"); kfree(xceiv_data); return -ENODEV; } /* Enable USB LDO */ regulator_enable(xceiv_data->bcm_hsotg_regulator); xceiv_data->regulator_enabled = true; /* Give 2ms to ramp up USBLDO */ mdelay(USBLDO_RAMP_UP_DELAY_IN_MS); xceiv_data->dev = &pdev->dev; xceiv_data->bcmpmu = bcmpmu; xceiv_data->otg_xceiver.xceiver.dev = xceiv_data->dev; xceiv_data->otg_xceiver.xceiver.label = "bcmpmu_otg_xceiv"; xceiv_data->host = false; xceiv_data->vbus_enabled = false; /* Create a work queue for OTG work items */ xceiv_data->bcm_otg_work_queue = create_workqueue("bcm_otg_events"); if (xceiv_data->bcm_otg_work_queue == NULL) { dev_warn(&pdev->dev, "BCM OTG events work queue creation failed\n"); bcmpmu_otg_free_regulator(xceiv_data); kfree(xceiv_data); return -ENOMEM; } /* Create one work item per deferrable function */ INIT_WORK(&xceiv_data->bcm_otg_vbus_invalid_work, bcmpmu_otg_xceiv_vbus_invalid_handler); INIT_WORK(&xceiv_data->bcm_otg_vbus_valid_work, bcmpmu_otg_xceiv_vbus_valid_handler); INIT_WORK(&xceiv_data->bcm_otg_vbus_a_invalid_work, bcmpmu_otg_xceiv_vbus_a_invalid_handler); INIT_WORK(&xceiv_data->bcm_otg_vbus_a_valid_work, bcmpmu_otg_xceiv_vbus_a_valid_handler); INIT_WORK(&xceiv_data->bcm_otg_id_status_change_work, bcmpmu_otg_xceiv_id_change_handler); INIT_WORK(&xceiv_data->bcm_otg_chg_detect_work, bcmpmu_otg_xceiv_chg_detect_handler); INIT_WORK(&xceiv_data->bcm_otg_sess_end_srp_work, bcmpmu_otg_xceiv_sess_end_srp_handler); INIT_DELAYED_WORK(&xceiv_data->bcm_otg_delayed_adp_work, bcmpmu_otg_xceiv_delayed_adp_handler); /* Initial value for previous OTG ID value. * 0 means unsupported */ xceiv_data->prev_otg_id = 0; /* Charger type not known yet */ xceiv_data->usb_charger_type = PMU_USB_TYPE_NONE; xceiv_data->otg_xceiver.xceiver.state = OTG_STATE_UNDEFINED; xceiv_data->otg_xceiver.xceiver.set_vbus = bcmpmu_otg_xceiv_set_vbus; xceiv_data->otg_xceiver.xceiver.set_peripheral = bcmpmu_otg_xceiv_set_peripheral; xceiv_data->otg_xceiver.xceiver.set_host = bcmpmu_otg_xceiv_set_host; xceiv_data->otg_xceiver.xceiver.shutdown = bcmpmu_otg_xceiv_shutdown; xceiv_data->otg_xceiver.xceiver.init = bcmpmu_otg_xceiv_start; xceiv_data->otg_xceiver.xceiver.set_power = bcmpmu_otg_xceiv_set_vbus_power; xceiv_data->otg_xceiver.xceiver.set_delayed_adp = bcmpmu_otg_xceiv_set_delayed_adp; xceiv_data->otg_xceiver.xceiver.set_srp_reqd = bcmpmu_otg_xceiv_set_srp_reqd_handler; xceiv_data->otg_xceiver.xceiver.pullup_on = bcmpmu_otg_xceiv_pullup_on; xceiv_data->otg_xceiver.xceiver.set_otg_enable = bcmpmu_otg_xceiv_set_otg_enable; xceiv_data->otg_xceiver.xceiver.set_suspend = bcmpmu_otg_xceiv_set_suspend; ATOMIC_INIT_NOTIFIER_HEAD(&xceiv_data->otg_xceiver.xceiver.notifier); xceiv_data->bcm_otg_vbus_validity_notifier.notifier_call = bcmpmu_otg_xceiv_vbus_notif_handler; bcmpmu_add_notifier(BCMPMU_USB_EVENT_VBUS_VALID, &xceiv_data->bcm_otg_vbus_validity_notifier); xceiv_data->bcm_otg_vbus_invalidity_notifier.notifier_call = bcmpmu_otg_xceiv_vbus_invalid_notif_handler; bcmpmu_add_notifier(BCMPMU_USB_EVENT_VBUS_INVALID, &xceiv_data->bcm_otg_vbus_invalidity_notifier); bcmpmu_add_notifier(BCMPMU_USB_EVENT_SESSION_INVALID, &xceiv_data->bcm_otg_vbus_validity_notifier); xceiv_data->bcm_otg_id_chg_notifier.notifier_call = bcmpmu_otg_xceiv_id_chg_notif_handler; bcmpmu_add_notifier(BCMPMU_USB_EVENT_ID_CHANGE, &xceiv_data->bcm_otg_id_chg_notifier); xceiv_data->bcm_otg_chg_detection_notifier.notifier_call = bcmpmu_otg_xceiv_chg_detection_notif_handler; bcmpmu_add_notifier(BCMPMU_USB_EVENT_USB_DETECTION, &xceiv_data->bcm_otg_chg_detection_notifier); wake_lock_init(&xceiv_data->otg_xceiver.xceiver_wake_lock, WAKE_LOCK_SUSPEND, "otg_xcvr_wakelock"); #ifdef CONFIG_USB_OTG init_timer(&xceiv_data->otg_xceiver.srp_failure_timer); xceiv_data->otg_xceiver.srp_failure_timer.data = (unsigned long)xceiv_data; xceiv_data->otg_xceiver.srp_failure_timer.function = bcmpmu_otg_xceiv_srp_failure_handler; init_timer(&xceiv_data->otg_xceiver.sess_end_srp_timer); xceiv_data->otg_xceiver.sess_end_srp_timer.data = (unsigned long)xceiv_data; xceiv_data->otg_xceiver.sess_end_srp_timer.function = bcmpmu_otg_xceiv_sess_end_srp_timer_handler; error = bcm_otg_adp_init(xceiv_data); if (error) goto error_attr_host; #endif otg_set_transceiver(&xceiv_data->otg_xceiver.xceiver); local_otg_xceiver = &xceiv_data->otg_xceiver.xceiver; platform_set_drvdata(pdev, xceiv_data); error = device_create_file(&pdev->dev, &dev_attr_host); if (error) { dev_warn(&pdev->dev, "Failed to create HOST file\n"); goto error_attr_host;; } error = device_create_file(&pdev->dev, &dev_attr_vbus); if (error) { dev_warn(&pdev->dev, "Failed to create VBUS file\n"); goto error_attr_vbus; } error = device_create_file(&pdev->dev, &dev_attr_wake); if (error) { dev_warn(&pdev->dev, "Failed to create WAKE file\n"); goto error_attr_wake; } /* Save original ID value */ bcmpmu_usb_get(xceiv_data->bcmpmu, BCMPMU_USB_CTRL_GET_ID_VALUE, &xceiv_data->prev_otg_id); /* Check if we should default to A-device */ xceiv_data->otg_xceiver.xceiver.default_a = bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) || bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data); bcmpmu_otg_xceiv_set_def_state(xceiv_data, xceiv_data->otg_xceiver.xceiver.default_a); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); dev_info(&pdev->dev, "Probing successful\n"); return 0; error_attr_wake: device_remove_file(xceiv_data->dev, &dev_attr_vbus); error_attr_vbus: device_remove_file(xceiv_data->dev, &dev_attr_host); error_attr_host: wake_lock_destroy(&xceiv_data->otg_xceiver.xceiver_wake_lock); destroy_workqueue(xceiv_data->bcm_otg_work_queue); bcmpmu_otg_free_regulator(xceiv_data); kfree(xceiv_data); return error; }