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;
}