static int max3355_probe(struct platform_device *pdev) { struct max3355_data *data; struct gpio_desc *gpiod; int irq, err; data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data), GFP_KERNEL); if (!data) return -ENOMEM; gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN); if (IS_ERR(gpiod)) { dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n"); return PTR_ERR(gpiod); } data->id_gpiod = gpiod; gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH); if (IS_ERR(gpiod)) { dev_err(&pdev->dev, "failed to get SHDN# GPIO\n"); return PTR_ERR(gpiod); } data->shdn_gpiod = gpiod; data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return PTR_ERR(data->edev); } err = devm_extcon_dev_register(&pdev->dev, data->edev); if (err < 0) { dev_err(&pdev->dev, "failed to register extcon device\n"); return err; } irq = gpiod_to_irq(data->id_gpiod); if (irq < 0) { dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n"); return irq; } err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq, IRQF_ONESHOT | IRQF_NO_SUSPEND | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, pdev->name, data); if (err < 0) { dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n"); return err; } platform_set_drvdata(pdev, data); /* Perform initial detection */ max3355_id_irq(irq, data); return 0; }
static int cht_wc_extcon_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); struct cht_wc_extcon_data *ext; int irq, ret; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL); if (!ext) return -ENOMEM; ext->dev = &pdev->dev; ext->regmap = pmic->regmap; ext->previous_cable = EXTCON_NONE; /* Initialize extcon device */ ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables); if (IS_ERR(ext->edev)) return PTR_ERR(ext->edev); /* * When a host-cable is detected the BIOS enables an external 5v boost * converter to power connected devices there are 2 problems with this: * 1) This gets seen by the external battery charger as a valid Vbus * supply and it then tries to feed Vsys from this creating a * feedback loop which causes aprox. 300 mA extra battery drain * (and unless we drive the external-charger-disable pin high it * also tries to charge the battery causing even more feedback). * 2) This gets seen by the pwrsrc block as a SDP USB Vbus supply * Since the external battery charger has its own 5v boost converter * which does not have these issues, we simply turn the separate * external 5v boost converter off and leave it off entirely. */ cht_wc_extcon_set_5v_boost(ext, false); /* Enable sw control */ ret = cht_wc_extcon_sw_control(ext, true); if (ret) return ret; /* Register extcon device */ ret = devm_extcon_dev_register(ext->dev, ext->edev); if (ret) { dev_err(ext->dev, "Error registering extcon device: %d\n", ret); goto disable_sw_control; } /* Route D+ and D- to PMIC for initial charger detection */ cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); /* Get initial state */ cht_wc_extcon_pwrsrc_event(ext); ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr, IRQF_ONESHOT, pdev->name, ext); if (ret) { dev_err(ext->dev, "Error requesting interrupt: %d\n", ret); goto disable_sw_control; } /* Unmask irqs */ ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND | CHT_WC_PWRSRC_ID_FLOAT)); if (ret) { dev_err(ext->dev, "Error writing irq-mask: %d\n", ret); goto disable_sw_control; } platform_set_drvdata(pdev, ext); return 0; disable_sw_control: cht_wc_extcon_sw_control(ext, false); return ret; }
static int max77693_muic_probe(struct platform_device *pdev) { struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); struct max77693_muic_info *info; struct max77693_reg_data *init_data; int num_init_data; int delay_jiffies; int ret; int i; unsigned int id; info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; info->max77693 = max77693; if (info->max77693->regmap_muic) { dev_dbg(&pdev->dev, "allocate register map\n"); } else { info->max77693->regmap_muic = devm_regmap_init_i2c( info->max77693->i2c_muic, &max77693_muic_regmap_config); if (IS_ERR(info->max77693->regmap_muic)) { ret = PTR_ERR(info->max77693->regmap_muic); dev_err(max77693->dev, "failed to allocate register map: %d\n", ret); return ret; } } /* Register input device for button of dock device */ info->dock = devm_input_allocate_device(&pdev->dev); if (!info->dock) { dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__); return -ENOMEM; } info->dock->name = "max77693-muic/dock"; info->dock->phys = "max77693-muic/extcon"; info->dock->dev.parent = &pdev->dev; __set_bit(EV_REP, info->dock->evbit); input_set_capability(info->dock, EV_KEY, KEY_VOLUMEUP); input_set_capability(info->dock, EV_KEY, KEY_VOLUMEDOWN); input_set_capability(info->dock, EV_KEY, KEY_PLAYPAUSE); input_set_capability(info->dock, EV_KEY, KEY_PREVIOUSSONG); input_set_capability(info->dock, EV_KEY, KEY_NEXTSONG); ret = input_register_device(info->dock); if (ret < 0) { dev_err(&pdev->dev, "Cannot register input device error(%d)\n", ret); return ret; } platform_set_drvdata(pdev, info); mutex_init(&info->mutex); INIT_WORK(&info->irq_work, max77693_muic_irq_work); /* Support irq domain for MAX77693 MUIC device */ for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { struct max77693_muic_irq *muic_irq = &muic_irqs[i]; int virq; virq = regmap_irq_get_virq(max77693->irq_data_muic, muic_irq->irq); if (virq <= 0) return -EINVAL; muic_irq->virq = virq; ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, max77693_muic_irq_handler, IRQF_NO_SUSPEND, muic_irq->name, info); if (ret) { dev_err(&pdev->dev, "failed: irq request (IRQ: %d, error :%d)\n", muic_irq->irq, ret); return ret; } } /* Initialize extcon device */ info->edev = devm_extcon_dev_allocate(&pdev->dev, max77693_extcon_cable); if (IS_ERR(info->edev)) { dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); return -ENOMEM; } ret = devm_extcon_dev_register(&pdev->dev, info->edev); if (ret) { dev_err(&pdev->dev, "failed to register extcon device\n"); return ret; } /* Initialize MUIC register by using platform data or default data */ if (pdata && pdata->muic_data) { init_data = pdata->muic_data->init_data; num_init_data = pdata->muic_data->num_init_data; } else { init_data = default_init_data; num_init_data = ARRAY_SIZE(default_init_data); } for (i = 0; i < num_init_data; i++) { regmap_write(info->max77693->regmap_muic, init_data[i].addr, init_data[i].data); } if (pdata && pdata->muic_data) { struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; /* * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB * h/w path of COMP2/COMN1 on CONTROL1 register. */ if (muic_pdata->path_uart) info->path_uart = muic_pdata->path_uart; else info->path_uart = MAX77693_CONTROL1_SW_UART; if (muic_pdata->path_usb) info->path_usb = muic_pdata->path_usb; else info->path_usb = MAX77693_CONTROL1_SW_USB; /* * Default delay time for detecting cable state * after certain time. */ if (muic_pdata->detcable_delay_ms) delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); else delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } else { info->path_usb = MAX77693_CONTROL1_SW_USB; info->path_uart = MAX77693_CONTROL1_SW_UART; delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } /* Set initial path for UART */ max77693_muic_set_path(info, info->path_uart, true); /* Check revision number of MUIC device*/ ret = regmap_read(info->max77693->regmap_muic, MAX77693_MUIC_REG_ID, &id); if (ret < 0) { dev_err(&pdev->dev, "failed to read revision number\n"); return ret; } dev_info(info->dev, "device ID : 0x%x\n", id); /* Set ADC debounce time */ max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); /* * Detect accessory after completing the initialization of platform * * - Use delayed workqueue to detect cable state and then * notify cable state to notifiee/platform through uevent. * After completing the booting of platform, the extcon provider * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq); queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, delay_jiffies); return ret; }
static int max8997_muic_probe(struct platform_device *pdev) { struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); struct max8997_muic_info *info; int delay_jiffies; int ret, i; info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; info->muic = max8997->muic; platform_set_drvdata(pdev, info); mutex_init(&info->mutex); INIT_WORK(&info->irq_work, max8997_muic_irq_work); for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { struct max8997_muic_irq *muic_irq = &muic_irqs[i]; unsigned int virq = 0; virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq); if (!virq) { ret = -EINVAL; goto err_irq; } muic_irq->virq = virq; ret = request_threaded_irq(virq, NULL, max8997_muic_irq_handler, IRQF_NO_SUSPEND, muic_irq->name, info); if (ret) { dev_err(&pdev->dev, "failed: irq request (IRQ: %d, error :%d)\n", muic_irq->irq, ret); goto err_irq; } } /* External connector */ info->edev = devm_extcon_dev_allocate(&pdev->dev, max8997_extcon_cable); if (IS_ERR(info->edev)) { dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); ret = -ENOMEM; goto err_irq; } ret = devm_extcon_dev_register(&pdev->dev, info->edev); if (ret) { dev_err(&pdev->dev, "failed to register extcon device\n"); goto err_irq; } if (pdata && pdata->muic_pdata) { struct max8997_muic_platform_data *muic_pdata = pdata->muic_pdata; /* Initialize registers according to platform data */ for (i = 0; i < muic_pdata->num_init_data; i++) { max8997_write_reg(info->muic, muic_pdata->init_data[i].addr, muic_pdata->init_data[i].data); } /* * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB * h/w path of COMP2/COMN1 on CONTROL1 register. */ if (muic_pdata->path_uart) info->path_uart = muic_pdata->path_uart; else info->path_uart = CONTROL1_SW_UART; if (muic_pdata->path_usb) info->path_usb = muic_pdata->path_usb; else info->path_usb = CONTROL1_SW_USB; /* * Default delay time for detecting cable state * after certain time. */ if (muic_pdata->detcable_delay_ms) delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); else delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } else { info->path_uart = CONTROL1_SW_UART; info->path_usb = CONTROL1_SW_USB; delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } /* Set initial path for UART */ max8997_muic_set_path(info, info->path_uart, true); /* Set ADC debounce time */ max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); /* * Detect accessory after completing the initialization of platform * * - Use delayed workqueue to detect cable state and then * notify cable state to notifiee/platform through uevent. * After completing the booting of platform, the extcon provider * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq); queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, delay_jiffies); return 0; err_irq: while (--i >= 0) free_irq(muic_irqs[i].virq, info); return ret; }
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rcar_gen3_chan *channel; struct phy_provider *provider; struct resource *res; int irq; if (!dev->of_node) { dev_err(dev, "This driver needs device tree\n"); return -EINVAL; } channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); if (!channel) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); channel->base = devm_ioremap_resource(dev, res); if (IS_ERR(channel->base)) return PTR_ERR(channel->base); /* call request_irq for OTG */ irq = platform_get_irq(pdev, 0); if (irq >= 0) { int ret; irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, IRQF_SHARED, dev_name(dev), channel); if (irq < 0) dev_err(dev, "No irq handler (%d)\n", irq); channel->has_otg = true; channel->extcon = devm_extcon_dev_allocate(dev, rcar_gen3_phy_cable); if (IS_ERR(channel->extcon)) return PTR_ERR(channel->extcon); ret = devm_extcon_dev_register(dev, channel->extcon); if (ret < 0) { dev_err(dev, "Failed to register extcon\n"); return ret; } } /* devm_phy_create() will call pm_runtime_enable(dev); */ channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops); if (IS_ERR(channel->phy)) { dev_err(dev, "Failed to create USB2 PHY\n"); return PTR_ERR(channel->phy); } channel->vbus = devm_regulator_get_optional(dev, "vbus"); if (IS_ERR(channel->vbus)) { if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) return PTR_ERR(channel->vbus); channel->vbus = NULL; } phy_set_drvdata(channel->phy, channel); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (IS_ERR(provider)) dev_err(dev, "Failed to register PHY provider\n"); return PTR_ERR_OR_ZERO(provider); }
static int axp288_extcon_probe(struct platform_device *pdev) { struct axp288_extcon_info *info; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); int ret, i, pirq, gpio; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->pdata = pdev->dev.platform_data; if (!info->pdata) { /* Try ACPI provided pdata via device properties */ if (!device_property_present(&pdev->dev, "axp288_extcon_data\n")) dev_err(&pdev->dev, "failed to get platform data\n"); return -ENODEV; } platform_set_drvdata(pdev, info); axp288_extcon_log_rsi(info); /* Initialize extcon device */ info->edev = devm_extcon_dev_allocate(&pdev->dev, axp288_extcon_cables); if (IS_ERR(info->edev)) { dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); return PTR_ERR(info->edev); } /* Register extcon device */ ret = devm_extcon_dev_register(&pdev->dev, info->edev); if (ret) { dev_err(&pdev->dev, "failed to register extcon device\n"); return ret; } /* Get otg transceiver phy */ info->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR(info->otg)) { dev_err(&pdev->dev, "failed to get otg transceiver\n"); return PTR_ERR(info->otg); } /* Set up gpio control for USB Mux */ if (info->pdata->gpio_mux_cntl) { gpio = desc_to_gpio(info->pdata->gpio_mux_cntl); ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX"); if (ret < 0) { dev_err(&pdev->dev, "failed to request the gpio=%d\n", gpio); return ret; } gpiod_direction_output(info->pdata->gpio_mux_cntl, EXTCON_GPIO_MUX_SEL_PMIC); } for (i = 0; i < EXTCON_IRQ_END; i++) { pirq = platform_get_irq(pdev, i); info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); if (info->irq[i] < 0) { dev_err(&pdev->dev, "failed to get virtual interrupt=%d\n", pirq); ret = info->irq[i]; return ret; } ret = devm_request_threaded_irq(&pdev->dev, info->irq[i], NULL, axp288_extcon_isr, IRQF_ONESHOT | IRQF_NO_SUSPEND, pdev->name, info); if (ret) { dev_err(&pdev->dev, "failed to request interrupt=%d\n", info->irq[i]); return ret; } } /* Enable interrupts */ axp288_extcon_enable_irq(info); return 0; }
static int max14577_muic_probe(struct platform_device *pdev) { struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); struct max14577_muic_info *info; int delay_jiffies; int ret; int i; u8 id; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; info->max14577 = max14577; platform_set_drvdata(pdev, info); mutex_init(&info->mutex); INIT_WORK(&info->irq_work, max14577_muic_irq_work); switch (max14577->dev_type) { case MAXIM_DEVICE_TYPE_MAX77836: info->muic_irqs = max77836_muic_irqs; info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs); break; case MAXIM_DEVICE_TYPE_MAX14577: default: info->muic_irqs = max14577_muic_irqs; info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs); } /* Support irq domain for max14577 MUIC device */ for (i = 0; i < info->muic_irqs_num; i++) { struct max14577_muic_irq *muic_irq = &info->muic_irqs[i]; int virq = 0; virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq); if (virq <= 0) return -EINVAL; muic_irq->virq = virq; ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, max14577_muic_irq_handler, IRQF_NO_SUSPEND, muic_irq->name, info); if (ret) { dev_err(&pdev->dev, "failed: irq request (IRQ: %d, error :%d)\n", muic_irq->irq, ret); return ret; } } /* Initialize extcon device */ info->edev = devm_extcon_dev_allocate(&pdev->dev, max14577_extcon_cable); if (IS_ERR(info->edev)) { dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); return -ENOMEM; } ret = devm_extcon_dev_register(&pdev->dev, info->edev); if (ret) { dev_err(&pdev->dev, "failed to register extcon device\n"); return ret; } /* Default h/w line path */ info->path_usb = CTRL1_SW_USB; info->path_uart = CTRL1_SW_UART; delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); /* Set initial path for UART */ max14577_muic_set_path(info, info->path_uart, true); /* Check revision number of MUIC device*/ ret = max14577_read_reg(info->max14577->regmap, MAX14577_REG_DEVICEID, &id); if (ret < 0) { dev_err(&pdev->dev, "failed to read revision number\n"); return ret; } dev_info(info->dev, "device ID : 0x%x\n", id); /* Set ADC debounce time */ max14577_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); /* * Detect accessory after completing the initialization of platform * * - Use delayed workqueue to detect cable state and then * notify cable state to notifiee/platform through uevent. * After completing the booting of platform, the extcon provider * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max14577_muic_detect_cable_wq); queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, delay_jiffies); return ret; }
static int mrfld_extcon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); struct regmap *regmap = pmic->regmap; struct mrfld_extcon_data *data; unsigned int id; int irq, ret; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->dev = dev; data->regmap = regmap; data->edev = devm_extcon_dev_allocate(dev, mrfld_extcon_cable); if (IS_ERR(data->edev)) return -ENOMEM; ret = devm_extcon_dev_register(dev, data->edev); if (ret < 0) { dev_err(dev, "can't register extcon device: %d\n", ret); return ret; } ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_extcon_interrupt, IRQF_ONESHOT | IRQF_SHARED, pdev->name, data); if (ret) { dev_err(dev, "can't register IRQ handler: %d\n", ret); return ret; } ret = regmap_read(regmap, BCOVE_ID, &id); if (ret) { dev_err(dev, "can't read PMIC ID: %d\n", ret); return ret; } data->id = id; ret = mrfld_extcon_sw_control(data, true); if (ret) return ret; /* Get initial state */ mrfld_extcon_role_detect(data); mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR); mrfld_extcon_clear(data, BCOVE_MCHGRIRQ1, BCOVE_CHGRIRQ_ALL); mrfld_extcon_set(data, BCOVE_USBIDCTRL, BCOVE_USBIDCTRL_ALL); platform_set_drvdata(pdev, data); return 0; }
static int palmas_usb_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct palmas_usb *palmas_usb; int status; palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; if (node && !pdata) { palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup"); palmas_usb->enable_id_detection = of_property_read_bool(node, "ti,enable-id-detection"); palmas_usb->enable_vbus_detection = of_property_read_bool(node, "ti,enable-vbus-detection"); } else { palmas_usb->wakeup = true; palmas_usb->enable_id_detection = true; palmas_usb->enable_vbus_detection = true; if (pdata) palmas_usb->wakeup = pdata->wakeup; } palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); if (IS_ERR(palmas_usb->id_gpiod)) { dev_err(&pdev->dev, "failed to get id gpio\n"); return PTR_ERR(palmas_usb->id_gpiod); } palmas_usb->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", GPIOD_IN); if (IS_ERR(palmas_usb->vbus_gpiod)) { dev_err(&pdev->dev, "failed to get vbus gpio\n"); return PTR_ERR(palmas_usb->vbus_gpiod); } if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) { palmas_usb->enable_id_detection = false; palmas_usb->enable_gpio_id_detection = true; } if (palmas_usb->enable_vbus_detection && palmas_usb->vbus_gpiod) { palmas_usb->enable_vbus_detection = false; palmas_usb->enable_gpio_vbus_detection = true; } if (palmas_usb->enable_gpio_id_detection) { u32 debounce; if (of_property_read_u32(node, "debounce-delay-ms", &debounce)) debounce = USB_GPIO_DEBOUNCE_MS; status = gpiod_set_debounce(palmas_usb->id_gpiod, debounce * 1000); if (status < 0) palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); } INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev, palmas_extcon_cable); if (IS_ERR(palmas_usb->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; } status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { dev_err(&pdev->dev, "failed to register extcon device\n"); return status; } if (palmas_usb->enable_id_detection) { palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_OTG_IRQ); palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->id_irq, status); return status; } } else if (palmas_usb->enable_gpio_id_detection) { palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod); if (palmas_usb->gpio_id_irq < 0) { dev_err(&pdev->dev, "failed to get id irq\n"); return palmas_usb->gpio_id_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_id_irq, NULL, palmas_gpio_id_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for id irq\n"); return status; } } if (palmas_usb->enable_vbus_detection) { palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->vbus_irq, status); return status; } } else if (palmas_usb->enable_gpio_vbus_detection) { /* remux GPIO_1 as VBUSDET */ status = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE, PALMAS_PRIMARY_SECONDARY_PAD1, PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK, (1 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)); if (status < 0) { dev_err(&pdev->dev, "can't remux GPIO1\n"); return status; } palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->gpio_vbus_irq = gpiod_to_irq(palmas_usb->vbus_gpiod); if (palmas_usb->gpio_vbus_irq < 0) { dev_err(&pdev->dev, "failed to get vbus irq\n"); return palmas_usb->gpio_vbus_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for vbus irq\n"); return status; } } palmas_enable_irq(palmas_usb); /* perform initial detection */ if (palmas_usb->enable_gpio_vbus_detection) palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb); palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); device_set_wakeup_capable(&pdev->dev, true); return 0; }
static int palmas_usb_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct palmas_usb *palmas_usb; int status; palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; if (node && !pdata) { palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup"); palmas_usb->enable_id_detection = of_property_read_bool(node, "ti,enable-id-detection"); palmas_usb->enable_vbus_detection = of_property_read_bool(node, "ti,enable-vbus-detection"); } else { palmas_usb->wakeup = true; palmas_usb->enable_id_detection = true; palmas_usb->enable_vbus_detection = true; if (pdata) palmas_usb->wakeup = pdata->wakeup; } palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_OTG_IRQ); palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_IRQ); palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_IRQ); palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev, palmas_extcon_cable); if (IS_ERR(palmas_usb->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; } palmas_usb->edev->name = kstrdup(node->name, GFP_KERNEL); palmas_usb->edev->mutually_exclusive = mutually_exclusive; status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { dev_err(&pdev->dev, "failed to register extcon device\n"); kfree(palmas_usb->edev->name); return status; } if (palmas_usb->enable_id_detection) { status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT | IRQF_EARLY_RESUME, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->id_irq, status); kfree(palmas_usb->edev->name); return status; } } if (palmas_usb->enable_vbus_detection) { status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT | IRQF_EARLY_RESUME, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->vbus_irq, status); kfree(palmas_usb->edev->name); return status; } } palmas_enable_irq(palmas_usb); device_set_wakeup_capable(&pdev->dev, true); return 0; }