static ssize_t bt_test_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bt_rfkill_info *bt_info = dev_get_drvdata(dev); if(bt_info->bt_test_mode) return sprintf(buf, "1\n"); mutex_lock(&bt_info->bt_lock); if(mx_is_factory_test_mode(MX_FACTORY_TEST_BT)) { msleep(100); if(mx_is_factory_test_mode(MX_FACTORY_TEST_BT)) { printk("in BT_TEST_MODE\n"); bt_info->bt_test_mode = 1; //test mode bt_info->monitor_wqueue = create_freezable_workqueue("wifi_test_led_wqueue"); INIT_DELAYED_WORK_DEFERRABLE(&bt_info->test_work, test_work); INIT_DELAYED_WORK_DEFERRABLE(&bt_info->led_delay_on_work, led_delay_on_work); queue_delayed_work(bt_info->monitor_wqueue, &bt_info->led_delay_on_work, msecs_to_jiffies(BT_LED_DELAY)); } } mutex_unlock(&bt_info->bt_lock); return sprintf(buf, "%d\n", bt_info->bt_test_mode); }
static int bcmsdh_sdmmc_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret = 0; if (func == NULL) return -EINVAL; sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); sd_info(("sdio_device: 0x%04x\n", func->device)); sd_info(("Function#: 0x%04x\n", func->num)); /* 4318 doesn't have function 2 */ if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) ret = sdioh_probe(func); #ifdef CONFIG_MACH_NOTLE if (func->num == 2) { sdmmc_pm_workqueue = create_freezable_workqueue("bcmsdh_sdmmc"); if (IS_ERR(sdmmc_pm_workqueue)) { sd_err(("bcmsdh fail to create workqueue\n")); return -EINVAL; } INIT_DELAYED_WORK(&bcmshd_resume_work, bcmshd_resume_delayed_work_fn); } #endif return ret; }
static int modem_sound_probe(struct platform_device *pdev) { int ret = 0; struct modem_sound_data *pdata = pdev->dev.platform_data; if(!pdata) return -1; ret = misc_register(&modem_sound_dev); if (ret < 0){ printk("modem register err!\n"); return ret; } sema_init(&pdata->power_sem,1); pdata->wq = create_freezable_workqueue("modem_sound"); INIT_WORK(&pdata->work, modem_sound_delay_power_downup); modem_sound = pdata; #if defined(CONFIG_SND_RK_SOC_RK2928)|| defined(CONFIG_SND_RK29_SOC_RK610_PHONEPAD) set_codec_spk = call_set_spk; #endif #ifdef CONFIG_SND_SOC_ES8323_PCM set_codec_for_pcm_modem = set_es8323; #endif printk("%s:modem sound initialized\n",__FUNCTION__); return ret; }
static int tz_start(struct devfreq *devfreq) { struct devfreq_msm_adreno_tz_data *priv; unsigned int tz_pwrlevels[MSM_ADRENO_MAX_PWRLEVELS + 1]; int i, out, ret; unsigned int version; struct msm_adreno_extended_profile *gpu_profile = container_of( (devfreq->profile), struct msm_adreno_extended_profile, profile); /* * Assuming that we have only one instance of the adreno device * connected to this governor, * can safely restore the pointer to the governor private data * from the container of the device profile */ devfreq->data = gpu_profile->private_data; partner_gpu_profile = gpu_profile; priv = devfreq->data; priv->nb.notifier_call = tz_notify; out = 1; if (devfreq->profile->max_state < MSM_ADRENO_MAX_PWRLEVELS) { for (i = 0; i < devfreq->profile->max_state; i++) tz_pwrlevels[out++] = devfreq->profile->freq_table[i]; tz_pwrlevels[0] = i; } else { pr_err(TAG "tz_pwrlevels[] is too short\n"); return -EINVAL; } gpu_profile->partner_wq = create_freezable_workqueue ("governor_msm_adreno_tz_wq"); INIT_WORK(&gpu_profile->partner_start_event_ws, do_partner_start_event); INIT_WORK(&gpu_profile->partner_stop_event_ws, do_partner_stop_event); INIT_WORK(&gpu_profile->partner_suspend_event_ws, do_partner_suspend_event); INIT_WORK(&gpu_profile->partner_resume_event_ws, do_partner_resume_event); ret = tz_init(priv, tz_pwrlevels, sizeof(tz_pwrlevels), &version, sizeof(version)); if (ret != 0 || version > MAX_TZ_VERSION) { pr_err(TAG "tz_init failed\n"); return ret; } return kgsl_devfreq_add_notifier(devfreq->dev.parent, &priv->nb); }
/* Create a swap chain work queue */ OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) /* * Calling alloc_ordered_workqueue with the WQ_FREEZABLE and * WQ_MEM_RECLAIM flags set, (currently) has the same effect as * calling create_freezable_workqueue. None of the other WQ * flags are valid. Setting WQ_MEM_RECLAIM should allow the * workqueue to continue to service the swap chain in low memory * conditions, preventing the driver from holding on to * resources longer than it needs to. */ #if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,37)) psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZEABLE | WQ_MEM_RECLAIM); #else psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM); #endif #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) psSwapChain->psWorkQueue = create_freezable_workqueue(DEVNAME); #else /* * Create a single-threaded, freezable, rt-prio workqueue. * Such workqueues are frozen with user threads when a system * suspends, before driver suspend entry points are called. * This ensures this driver will not call into the Linux * framebuffer driver after the latter is suspended. */ psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1); #endif #endif if (psSwapChain->psWorkQueue == NULL) { printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Couldn't create workqueue\n", __FUNCTION__, psSwapChain->uiFBDevID); return (OMAPLFB_ERROR_INIT_FAILURE); } return (OMAPLFB_OK); }
OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM); #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) psSwapChain->psWorkQueue = create_freezable_workqueue(DEVNAME); #else psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1); #endif #endif if (psSwapChain->psWorkQueue == NULL) { printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Couldn't create workqueue\n", __FUNCTION__, psSwapChain->uiFBDevID); return (OMAPLFB_ERROR_INIT_FAILURE); } return (OMAPLFB_OK); }
static int __init mmc_init(void) { int ret; wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND, "mmc_delayed_work"); #ifdef PATCH_SUSPEND_RESUME workqueue = create_freezable_workqueue("kmmcd"); #else workqueue = create_singlethread_workqueue("kmmcd"); #endif if (!workqueue) return -ENOMEM; ret = mmc_register_bus(); if (ret) goto destroy_workqueue; ret = mmc_register_host_class(); if (ret) goto unregister_bus; ret = sdio_register_bus(); if (ret) goto unregister_host_class; return 0; unregister_host_class: mmc_unregister_host_class(); unregister_bus: mmc_unregister_bus(); destroy_workqueue: destroy_workqueue(workqueue); return ret; }
/* PCI probe function */ static int __devinit ps_hdmi_hpd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int result = 0; hdmi_context_t *ctx = g_context; if (pdev == NULL || ctx == NULL) { pr_err("%s: called with NULL device or context\n", __func__); result = -EINVAL; return result; } /* Verify probe is called for the intended device */ if (pdev->device != PS_MSIC_PCI_DEVICE_ID) { pr_err("%s: called for wrong device id = 0x%x\n", __func__, pdev->device); result = -EINVAL; goto exit; } pr_debug("pci_enable_device for 0x%x\n", PS_MSIC_PCI_DEVICE_ID); result = pci_enable_device(pdev); if (result) { pr_err("%s: Failed to enable MSIC PCI device = 0x%x\n", __func__, PS_MSIC_PCI_DEVICE_ID); goto exit; } /* Map IO region for IRQ registers */ ctx->dev.irq_io_address = ioremap_nocache(PS_MSIC_VRINT_ADDR, PS_MSIC_VRINT_IOADDR_LEN); if (!ctx->dev.irq_io_address) { pr_err("%s: Failed to map IO region for MSIC IRQ\n", __func__); result = -ENOMEM; goto exit2; } ctx->irq_number = pdev->irq; pr_debug("%s: IRQ number assigned = %d\n", __func__, pdev->irq); result = request_threaded_irq(ctx->irq_number, ps_hdmi_irq_handler, ctx->hpd_callback, IRQF_SHARED, PS_HDMI_HPD_PCI_DRIVER_NAME, ctx->hpd_data); if (result) { pr_debug("%s: Register irq interrupt %d failed\n", __func__, ctx->irq_number); goto exit3; } /* Create Freezable workqueue for post resume HPD operations */ ctx->post_resume_wq = create_freezable_workqueue("MFLD Post-Resume WQ"); if (!ctx->post_resume_wq) { pr_debug("%s: Failed to create post-resume workqueue\n", __func__); goto exit3; } INIT_WORK(&ctx->post_resume_work, ps_post_resume_wq); return result; exit3: iounmap(ctx->dev.irq_io_address); exit2: pci_disable_device(pdev); exit: pci_dev_put(pdev); return result; }
/** * exynos_drd_switch_init - Initializes DRD role switch. * * @drd: Pointer to DRD controller structure. * * Returns 0 on success otherwise negative errno. */ int exynos_drd_switch_init(struct exynos_drd *drd) { struct dwc3_exynos_data *pdata = drd->pdata; struct exynos_drd_switch *drd_switch; int ret = 0; unsigned long irq_flags = 0; dev_dbg(drd->dev, "%s\n", __func__); drd_switch = devm_kzalloc(drd->dev, sizeof(struct exynos_drd_switch), GFP_KERNEL); if (!drd_switch) { dev_err(drd->dev, "not enough memory for DRD switch\n"); return -ENOMEM; } drd_switch->core = &drd->core; atomic_set(&drd_switch->sm_reset, 0); /* ID pin gpio IRQ */ drd_switch->id_irq = pdata->id_irq; if (drd_switch->id_irq < 0) dev_dbg(drd->dev, "cannot find ID irq\n"); init_timer(&drd_switch->id_db_timer); drd_switch->id_db_timer.data = (unsigned long) drd_switch; drd_switch->id_db_timer.function = exynos_drd_switch_debounce; /* VBus pin gpio IRQ */ drd_switch->vbus_irq = pdata->vbus_irq; if (drd_switch->vbus_irq < 0) dev_dbg(drd->dev, "cannot find VBUS irq\n"); init_timer(&drd_switch->vbus_db_timer); drd_switch->vbus_db_timer.data = (unsigned long) drd_switch; drd_switch->vbus_db_timer.function = exynos_drd_switch_debounce; irq_flags = pdata->irq_flags; drd_switch->otg.set_peripheral = exynos_drd_switch_set_peripheral; drd_switch->otg.set_host = exynos_drd_switch_set_host; /* Save for using by host and peripheral */ drd->core.otg = &drd_switch->otg; drd_switch->otg.phy = devm_kzalloc(drd->dev, sizeof(struct usb_phy), GFP_KERNEL); if (!drd_switch->otg.phy) { dev_err(drd->dev, "cannot allocate OTG phy\n"); return -ENOMEM; } drd_switch->otg.phy->otg = &drd_switch->otg; drd_switch->otg.phy->dev = drd->dev; #if 0 /* * TODO: we need to have support for multiple transceivers here. * Kernel > 3.5 should already have it. Now it works only for one * drd channel. */ ret = usb_set_transceiver(drd_switch->otg.phy); if (ret) { dev_err(drd->dev, "failed to set transceiver, already exists\n", __func__); goto err2; } #endif spin_lock_init(&drd_switch->lock); #if !defined(CONFIG_USB_HOST_NOTIFY) wake_lock_init(&drd_switch->wakelock, WAKE_LOCK_SUSPEND, "drd_switch"); #endif exynos_drd_switch_reset(drd, 0); drd_switch->wq = create_freezable_workqueue("drd_switch"); if (!drd_switch->wq) { dev_err(drd->dev, "cannot create workqueue\n"); ret = -ENOMEM; goto err_wq; } INIT_DELAYED_WORK(&drd_switch->work, exynos_drd_switch_work); if (drd_switch->id_irq >= 0) { ret = devm_request_irq(drd->dev, drd_switch->id_irq, exynos_drd_switch_id_interrupt, irq_flags, "drd_switch_id", drd_switch); if (ret) { dev_err(drd->dev, "cannot claim ID irq\n"); goto err_irq; } } if (drd_switch->vbus_irq >= 0) { ret = devm_request_irq(drd->dev, drd_switch->vbus_irq, exynos_drd_switch_vbus_interrupt, irq_flags, "drd_switch_vbus", drd_switch); if (ret) { dev_err(drd->dev, "cannot claim VBUS irq\n"); goto err_irq; } } ret = sysfs_create_group(&drd->dev->kobj, &exynos_drd_switch_attr_group); if (ret) { dev_err(drd->dev, "cannot create switch attributes\n"); goto err_irq; } dev_dbg(drd->dev, "DRD switch initialization finished normally\n"); return 0; err_irq: cancel_delayed_work_sync(&drd_switch->work); destroy_workqueue(drd_switch->wq); err_wq: #if !defined(CONFIG_USB_HOST_NOTIFY) wake_lock_destroy(&drd_switch->wakelock); #endif return ret; }
static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; pr_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery", chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, chg->psy_bat.properties = max8998_battery_props, chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props), chg->psy_bat.get_property = s3c_bat_get_property, chg->psy_bat.property_is_writeable = s3c_bat_property_is_writeable, chg->psy_bat.set_property = s3c_bat_set_property, chg->psy_usb.name = "usb", chg->psy_usb.type = POWER_SUPPLY_TYPE_USB, chg->psy_usb.supplied_to = supply_list, chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_usb.properties = s3c_power_properties, chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_usb.get_property = s3c_usb_get_property, chg->psy_ac.name = "ac", chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, chg->psy_ac.supplied_to = supply_list, chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_ac.properties = s3c_power_properties, chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_ac.get_property = s3c_ac_get_property, chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->bat_info.batt_temp = 100; //fake chg->bat_info.batt_percentage = 50; //fake, modem will bootup soon and update it... hopefully chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_update_reg(i2c, MAX8998_REG_CHGR1, /* disable */ (0x3 << MAX8998_SHIFT_RSTR), MAX8998_MASK_RSTR); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 6 Hr */ (0x2 << MAX8998_SHIFT_FT), MAX8998_MASK_FT); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 4.2V */ (0x0 << MAX8998_SHIFT_BATTSL), MAX8998_MASK_BATTSL); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 105c */ (0x0 << MAX8998_SHIFT_TMP), MAX8998_MASK_TMP); if (ret < 0) goto err_kfree; pr_info("%s : pmic interrupt registered\n", __func__); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_MASK_DCINR | MAX8998_MASK_DCINF)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_CHGRSTF_MASK); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, 0xFF); if (ret < 0) goto err_kfree; wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); INIT_WORK(&chg->bat_work, s3c_bat_work); chg->monitor_wqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_wake_lock; } chg->last_poll = alarm_get_elapsed_realtime(); alarm_init(&chg->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, s3c_battery_alarm); check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("Failed to register power supply psy_bat\n"); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("Failed to register power supply psy_usb\n"); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("Failed to register power supply psy_ac\n"); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("Failed to enable pmic irq wake\n"); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); alarm_cancel(&chg->alarm); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }
/** * ti_tpd_probe */ static int __devinit ti_tpd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct drm_device *dev = hdmi_priv ? hdmi_priv->dev : 0; struct drm_psb_private *dev_priv = dev ? psb_priv(dev) : 0; int ret = 0; PSB_DEBUG_ENTRY("\n"); if (pdev->device != TI_TPD_PCI_DEVICE_ID) { DRM_ERROR("%s: pciid = 0x%x is not ti_tpd pciid.\n", __func__, pdev->device); ret = -EINVAL; goto err0; } /* enable HDMI COMPANION CHIP device */ ret = pci_enable_device(pdev); if (ret) { DRM_ERROR("%s:Fail to enable pci devices\n", __func__); goto err0; } ret = gpio_request(CLV_TI_HPD_GPIO_PIN, "ti_tpd_hdmi_hpd"); if (ret) { DRM_ERROR("%s: Failed to request GPIO %d for kbd IRQ\n", __func__, CLV_TI_HPD_GPIO_PIN); goto err1; } ret = gpio_direction_input(CLV_TI_HPD_GPIO_PIN); if (ret) { DRM_ERROR("%s: Failed to set GPIO %d as input\n", __func__, CLV_TI_HPD_GPIO_PIN); goto err2; } ret = irq_set_irq_type(gpio_to_irq(CLV_TI_HPD_GPIO_PIN), IRQ_TYPE_EDGE_BOTH); if (ret) { DRM_ERROR("%s: Failed to set HDMI HPD IRQ type\n", __func__); goto err2; } if (dev_priv == NULL) { DRM_ERROR("%s: Invalid parameter", __func__); ret = -EINVAL; goto err2; } dev_priv->hpd_detect = create_freezable_workqueue("hpd_detect"); if (dev_priv->hpd_detect == NULL) { DRM_ERROR("%s: Creating workqueue failed", __func__); ret = -ENOMEM; goto err2; } ret = request_irq(gpio_to_irq(CLV_TI_HPD_GPIO_PIN), hdmi_hpd_handler, IRQF_SHARED, "hdmi_hpd_handler", (void *)hdmi_priv); if (ret) { DRM_ERROR("%s: Can not register GPIO %d IRQ!\n", __func__, CLV_TI_HPD_GPIO_PIN); goto err3; } PSB_DEBUG_ENTRY("%s: Requested HDMI HPD IRQ" "sussessfully.\n", __func__); return ret; err3: destroy_workqueue(dev_priv->hpd_detect); err2: gpio_free(CLV_TI_HPD_GPIO_PIN); err1: pci_disable_device(pdev); err0: pci_dev_put(pdev); DRM_ERROR("%s: request_irq failed. ret = %d.\n", __func__, ret); return ret; }
static irqreturn_t exynos4x12_tmu_irq_handler(int irq, void *id) { struct s5p_tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + EXYNOS4_TMU_INTSTAT) & 0x1FFFF; pr_info("EXYNOS4x12_tmu interrupt: INTSTAT = 0x%08x\n", status); /* To handle multiple interrupt pending, * interrupt by high temperature are serviced with priority. */ #if defined(CONFIG_TC_VOLTAGE) if (status & INTSTAT_FALL0) { info->tmu_state = TMU_STATUS_TC; __raw_writel(INTCLEARALL, info->tmu_base + EXYNOS4_TMU_INTCLEAR); exynos_interrupt_enable(info, 0); } else if (status & INTSTAT_RISE2) { info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR_RISE2, info->tmu_base + EXYNOS4_TMU_INTCLEAR); #else if (status & INTSTAT_RISE2) { info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR_RISE2, info->tmu_base + EXYNOS4_TMU_INTCLEAR); #endif } else if (status & INTSTAT_RISE1) { info->tmu_state = TMU_STATUS_WARNING; __raw_writel(INTCLEAR_RISE1, info->tmu_base + EXYNOS4_TMU_INTCLEAR); } else if (status & INTSTAT_RISE0) { info->tmu_state = TMU_STATUS_THROTTLED; __raw_writel(INTCLEAR_RISE0, info->tmu_base + EXYNOS4_TMU_INTCLEAR); } else { pr_err("%s: interrupt error\n", __func__); __raw_writel(INTCLEARALL, info->tmu_base + EXYNOS4_TMU_INTCLEAR); queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate / 2); return -ENODEV; } /* read current temperature & save */ info->last_temperature = get_curr_temp(info); queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); return IRQ_HANDLED; } static irqreturn_t exynos4210_tmu_irq_handler(int irq, void *id) { struct s5p_tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + EXYNOS4_TMU_INTSTAT); pr_info("EXYNOS4212_tmu interrupt: INTSTAT = 0x%08x\n", status); /* To handle multiple interrupt pending, * interrupt by high temperature are serviced with priority. */ if (status & TMU_INTSTAT2) { info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR2, info->tmu_base + EXYNOS4_TMU_INTCLEAR); } else if (status & TMU_INTSTAT1) { info->tmu_state = TMU_STATUS_WARNING; __raw_writel(INTCLEAR1, info->tmu_base + EXYNOS4_TMU_INTCLEAR); } else if (status & TMU_INTSTAT0) { info->tmu_state = TMU_STATUS_THROTTLED; __raw_writel(INTCLEAR0, info->tmu_base + EXYNOS4_TMU_INTCLEAR); } else { pr_err("%s: interrupt error\n", __func__); __raw_writel(INTCLEARALL, info->tmu_base + EXYNOS4_TMU_INTCLEAR); queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate / 2); return -ENODEV; } /* read current temperature & save */ info->last_temperature = get_curr_temp(info); queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); return IRQ_HANDLED; } #ifdef CONFIG_TMU_SYSFS static ssize_t s5p_tmu_show_curr_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct s5p_tmu_info *info = dev_get_drvdata(dev); unsigned int curr_temp; curr_temp = get_curr_temp(info); curr_temp *= 10; pr_info("curr temp = %d\n", curr_temp); return sprintf(buf, "%d\n", curr_temp); } static DEVICE_ATTR(curr_temp, S_IRUGO, s5p_tmu_show_curr_temp, NULL); #endif static int __devinit s5p_tmu_probe(struct platform_device *pdev) { struct s5p_tmu_info *info; struct s5p_platform_tmu *pdata; struct resource *res; unsigned int mask = (enable_mask & ENABLE_DBGMASK); int ret = 0; pr_debug("%s: probe=%p\n", __func__, pdev); info = kzalloc(sizeof(struct s5p_tmu_info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_nomem; } platform_set_drvdata(pdev, info); info->dev = &pdev->dev; info->tmu_state = TMU_STATUS_INIT; /* set cpufreq limit level at 1st_throttle & 2nd throttle */ pdata = info->dev->platform_data; if (pdata->cpufreq.limit_1st_throttle) exynos_cpufreq_get_level(pdata->cpufreq.limit_1st_throttle, &info->cpufreq_level_1st_throttle); if (pdata->cpufreq.limit_2nd_throttle) exynos_cpufreq_get_level(pdata->cpufreq.limit_2nd_throttle, &info->cpufreq_level_2nd_throttle); pr_info("@@@ %s: cpufreq_limit: 1st_throttle: %u, 2nd_throttle = %u\n", __func__, info->cpufreq_level_1st_throttle, info->cpufreq_level_2nd_throttle); #if defined(CONFIG_TC_VOLTAGE) /* Temperature compensated voltage */ if (exynos_find_cpufreq_level_by_volt(pdata->temp_compensate.arm_volt, &info->cpulevel_tc) < 0) { dev_err(&pdev->dev, "cpufreq_get_level error\n"); ret = -EINVAL; goto err_nores; } #ifdef CONFIG_BUSFREQ_OPP /* To lock bus frequency in OPP mode */ info->bus_dev = dev_get("exynos-busfreq"); if (info->bus_dev < 0) { dev_err(&pdev->dev, "Failed to get_dev\n"); ret = -EINVAL; goto err_nores; } if (exynos4x12_find_busfreq_by_volt(pdata->temp_compensate.bus_volt, &info->busfreq_tc)) { dev_err(&pdev->dev, "get_busfreq_value error\n"); ret = -EINVAL; goto err_nores; } #endif pr_info("%s: cpufreq_level[%u], busfreq_value[%u]\n", __func__, info->cpulevel_tc, info->busfreq_tc); #endif /* Map auto_refresh_rate of normal & tq0 mode */ info->auto_refresh_tq0 = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_TQ0); info->auto_refresh_normal = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_NORMAL); /* To poll current temp, set sampling rate to ONE second sampling */ info->sampling_rate = usecs_to_jiffies(1000 * 1000); /* 10sec monitroing */ info->monitor_period = usecs_to_jiffies(10000 * 1000); /* support test mode */ if (mask & ENABLE_TEST_MODE) set_temperature_params(info); else print_temperature_params(info); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get memory region resource\n"); ret = -ENODEV; goto err_nores; } info->ioarea = request_mem_region(res->start, res->end-res->start + 1, pdev->name); if (!(info->ioarea)) { dev_err(&pdev->dev, "failed to reserve memory region\n"); ret = -EBUSY; goto err_nores; } info->tmu_base = ioremap(res->start, (res->end - res->start) + 1); if (!(info->tmu_base)) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -ENOMEM; goto err_nomap; } tmu_monitor_wq = create_freezable_workqueue(dev_name(&pdev->dev)); if (!tmu_monitor_wq) { pr_info("Creation of tmu_monitor_wq failed\n"); ret = -ENOMEM; goto err_wq; } /* To support periodic temprature monitoring */ if (mask & ENABLE_TEMP_MON) { INIT_DELAYED_WORK_DEFERRABLE(&info->monitor, exynos4_poll_cur_temp); queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->monitor_period); } INIT_DELAYED_WORK_DEFERRABLE(&info->polling, exynos4_handler_tmu_state); info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal %d\n", info->irq); ret = -EINVAL; goto err_irq; } if (soc_is_exynos4210()) ret = request_irq(info->irq, exynos4210_tmu_irq_handler, IRQF_DISABLED, "s5p-tmu interrupt", info); else ret = request_irq(info->irq, exynos4x12_tmu_irq_handler, IRQF_DISABLED, "s5p-tmu interrupt", info); if (ret) { dev_err(&pdev->dev, "request_irq is failed. %d\n", ret); goto err_irq; } ret = device_create_file(&pdev->dev, &dev_attr_temperature); if (ret != 0) { pr_err("Failed to create temperatue file: %d\n", ret); goto err_sysfs_file1; } ret = device_create_file(&pdev->dev, &dev_attr_tmu_state); if (ret != 0) { pr_err("Failed to create tmu_state file: %d\n", ret); goto err_sysfs_file2; } ret = device_create_file(&pdev->dev, &dev_attr_lot_id); if (ret != 0) { pr_err("Failed to create lot id file: %d\n", ret); goto err_sysfs_file3; } ret = tmu_initialize(pdev); if (ret) goto err_init; #ifdef CONFIG_TMU_SYSFS ret = device_create_file(&pdev->dev, &dev_attr_curr_temp); if (ret < 0) { dev_err(&pdev->dev, "Failed to create sysfs group\n"); goto err_init; } #endif #ifdef CONFIG_TMU_DEBUG ret = device_create_file(&pdev->dev, &dev_attr_print_state); if (ret) { dev_err(&pdev->dev, "Failed to create tmu sysfs group\n\n"); return ret; } #endif #if defined(CONFIG_TC_VOLTAGE) /* s/w workaround for fast service when interrupt is not occured, * such as current temp is lower than tc interrupt temperature * or current temp is continuosly increased. */ if (get_curr_temp(info) <= pdata->ts.start_tc) { if (exynos_tc_volt(info, 1) < 0) pr_err("TMU: lock error!\n"); } #if defined(CONFIG_VIDEO_MALI400MP) if (mali_voltage_lock_init()) pr_err("Failed to initialize mail voltage lock.\n"); #endif #endif /* initialize tmu_state */ queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); return ret; err_init: device_remove_file(&pdev->dev, &dev_attr_lot_id); err_sysfs_file3: device_remove_file(&pdev->dev, &dev_attr_tmu_state); err_sysfs_file2: device_remove_file(&pdev->dev, &dev_attr_temperature); err_sysfs_file1: if (info->irq >= 0) free_irq(info->irq, info); err_irq: destroy_workqueue(tmu_monitor_wq); err_wq: iounmap(info->tmu_base); err_nomap: release_resource(info->ioarea); kfree(info->ioarea); err_nores: kfree(info); info = NULL; err_nomem: dev_err(&pdev->dev, "initialization failed.\n"); return ret; } static int __devinit s5p_tmu_remove(struct platform_device *pdev) { struct s5p_tmu_info *info = platform_get_drvdata(pdev); cancel_delayed_work(&info->polling); destroy_workqueue(tmu_monitor_wq); device_remove_file(&pdev->dev, &dev_attr_temperature); device_remove_file(&pdev->dev, &dev_attr_tmu_state); if (info->irq >= 0) free_irq(info->irq, info); iounmap(info->tmu_base); release_resource(info->ioarea); kfree(info->ioarea); kfree(info); info = NULL; pr_info("%s is removed\n", dev_name(&pdev->dev)); return 0; } #ifdef CONFIG_PM static int s5p_tmu_suspend(struct platform_device *pdev, pm_message_t state) { struct s5p_tmu_info *info = platform_get_drvdata(pdev); if (!info) return -EAGAIN; /* save register value */ info->reg_save[0] = __raw_readl(info->tmu_base + EXYNOS4_TMU_CONTROL); info->reg_save[1] = __raw_readl(info->tmu_base + EXYNOS4_TMU_SAMPLING_INTERNAL); info->reg_save[2] = __raw_readl(info->tmu_base + EXYNOS4_TMU_COUNTER_VALUE0); info->reg_save[3] = __raw_readl(info->tmu_base + EXYNOS4_TMU_COUNTER_VALUE1); info->reg_save[4] = __raw_readl(info->tmu_base + EXYNOS4_TMU_INTEN); if (soc_is_exynos4210()) { info->reg_save[5] = __raw_readl(info->tmu_base + EXYNOS4210_TMU_THRESHOLD_TEMP); info->reg_save[6] = __raw_readl(info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL0); info->reg_save[7] = __raw_readl(info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL1); info->reg_save[8] = __raw_readl(info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL2); info->reg_save[9] = __raw_readl(info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL3); } else { info->reg_save[5] = __raw_readl(info->tmu_base + EXYNOS4x12_TMU_TRESHOLD_TEMP_RISE); #if defined(CONFIG_TC_VOLTAGE) info->reg_save[6] = __raw_readl(info->tmu_base + EXYNOS4x12_TMU_TRESHOLD_TEMP_FALL); #endif } disable_irq(info->irq); return 0; } static int s5p_tmu_resume(struct platform_device *pdev) { struct s5p_tmu_info *info = platform_get_drvdata(pdev); struct s5p_platform_tmu *data; if (!info || !(info->dev)) return -EAGAIN; data = info->dev->platform_data; /* restore tmu register value */ __raw_writel(info->reg_save[0], info->tmu_base + EXYNOS4_TMU_CONTROL); __raw_writel(info->reg_save[1], info->tmu_base + EXYNOS4_TMU_SAMPLING_INTERNAL); __raw_writel(info->reg_save[2], info->tmu_base + EXYNOS4_TMU_COUNTER_VALUE0); __raw_writel(info->reg_save[3], info->tmu_base + EXYNOS4_TMU_COUNTER_VALUE1); if (soc_is_exynos4210()) { __raw_writel(info->reg_save[5], info->tmu_base + EXYNOS4210_TMU_THRESHOLD_TEMP); __raw_writel(info->reg_save[6], info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL0); __raw_writel(info->reg_save[7], info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL1); __raw_writel(info->reg_save[8], info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL2); __raw_writel(info->reg_save[9], info->tmu_base + EXYNOS4210_TMU_TRIG_LEVEL3); } else { __raw_writel(info->reg_save[5], info->tmu_base + EXYNOS4x12_TMU_TRESHOLD_TEMP_RISE); #if defined(CONFIG_TC_VOLTAGE) __raw_writel(info->reg_save[6], info->tmu_base + EXYNOS4x12_TMU_TRESHOLD_TEMP_FALL); #endif } __raw_writel(info->reg_save[4], info->tmu_base + EXYNOS4_TMU_INTEN); #if defined(CONFIG_TC_VOLTAGE) /* s/w workaround for fast service when interrupt is not occured, * such as current temp is lower than tc interrupt temperature * or current temp is continuosly increased.. */ mdelay(1); if (get_curr_temp(info) <= data->ts.start_tc) { if (exynos_tc_volt(info, 1) < 0) pr_err("TMU: lock error!\n"); } #endif /* Find out tmu_state after wakeup */ queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, 0); return 0; } #else #define s5p_tmu_suspend NULL #define s5p_tmu_resume NULL #endif static struct platform_driver s5p_tmu_driver = { .probe = s5p_tmu_probe, .remove = s5p_tmu_remove, .suspend = s5p_tmu_suspend, .resume = s5p_tmu_resume, .driver = { .name = "s5p-tmu", .owner = THIS_MODULE, }, }; static int __init s5p_tmu_driver_init(void) { return platform_driver_register(&s5p_tmu_driver); } static void __exit s5p_tmu_driver_exit(void) { platform_driver_unregister(&s5p_tmu_driver); }
static int __devinit tmu_probe(struct platform_device *pdev) { struct tmu_info *info; struct resource *res; int ret; if (dev_get_platdata(&pdev->dev) == NULL) { dev_err(&pdev->dev, "No platform data\n"); ret = -ENODEV; goto err_out; } info = devm_kzalloc(&pdev->dev, sizeof(struct tmu_info), GFP_KERNEL); if (info == NULL) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_out; } info->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get memory region resource\n"); ret = -ENODEV; goto err_out; } info->tmu_base = devm_request_and_ioremap(&pdev->dev, res); if (info->tmu_base == NULL) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -ENOMEM; goto err_out; } INIT_DELAYED_WORK_DEFERRABLE(&info->polling, tmu_monitor); tmu_monitor_wq = create_freezable_workqueue("tmu"); if (!tmu_monitor_wq) { dev_err(&pdev->dev, "Creation of tmu_monitor_wq failed\n"); ret = -EFAULT; goto err_out; } info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal\n"); ret = info->irq; goto err_wq; } platform_set_drvdata(pdev, info); ret = exynos_tmu_init(info); if (ret < 0) goto err_noinit; ret = request_irq(info->irq, tmu_irq, IRQF_DISABLED, "tmu", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq, ret); ret = -EBUSY; goto err_noinit; } tmu_debugfs = debugfs_create_file("tmu_dev_status", S_IRUGO, NULL, info, &tmu_dev_status_fops); if (IS_ERR_OR_NULL(tmu_debugfs)) { tmu_debugfs = NULL; dev_err(&pdev->dev, "%s: debugfs_create_file() failed\n", __func__); goto err_nodbgfs; } dev_info(&pdev->dev, "Tmu Initialization is sucessful...!\n"); return 0; err_nodbgfs: free_irq(info->irq, NULL); err_noinit: platform_set_drvdata(pdev, NULL); err_wq: destroy_workqueue(tmu_monitor_wq); err_out: dev_err(&pdev->dev, "initialization failed.\n"); return ret; }
static int __devinit s5p_tmu_probe(struct platform_device *pdev) { struct s5p_tmu_info *info; struct s5p_platform_tmu *pdata; struct resource *res; int ret = 0; pr_debug("%s: probe=%p\n", __func__, pdev); info = kzalloc(sizeof(struct s5p_tmu_info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_nomem; } platform_set_drvdata(pdev, info); info->dev = &pdev->dev; info->tmu_state = TMU_STATUS_INIT; /* set cpufreq limit level at 1st_throttle & 2nd throttle */ pdata = info->dev->platform_data; if (pdata->cpufreq.limit_1st_throttle) exynos_cpufreq_get_level(pdata->cpufreq.limit_1st_throttle, &info->cpufreq_level_1st_throttle); if (pdata->cpufreq.limit_2nd_throttle) exynos_cpufreq_get_level(pdata->cpufreq.limit_2nd_throttle, &info->cpufreq_level_2nd_throttle); pr_info("@@@ %s: cpufreq_limit: 1st_throttle: %d, 2nd_throttle = %d\n", __func__, info->cpufreq_level_1st_throttle, info->cpufreq_level_2nd_throttle); /* Map auto_refresh_rate of normal & tq0 mode */ info->auto_refresh_tq0 = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_TQ0); info->auto_refresh_normal = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_NORMAL); /* To poll current temp, set sampling rate to ONE second sampling */ info->sampling_rate = usecs_to_jiffies(1000 * 1000); /* 10sec monitroing */ info->monitor_period = usecs_to_jiffies(10000 * 1000); set_temperature_params(info); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get memory region resource\n"); ret = -ENODEV; goto err_nores; } info->ioarea = request_mem_region(res->start, res->end-res->start + 1, pdev->name); if (!(info->ioarea)) { dev_err(&pdev->dev, "failed to reserve memory region\n"); ret = -EBUSY; goto err_nores; } info->tmu_base = ioremap(res->start, (res->end - res->start) + 1); if (!(info->tmu_base)) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -EINVAL; goto err_nomap; } tmu_monitor_wq = create_freezable_workqueue(dev_name(&pdev->dev)); if (!tmu_monitor_wq) { pr_info("Creation of tmu_monitor_wq failed\n"); return -EFAULT; } #ifdef CONFIG_TMU_DEBUG INIT_DELAYED_WORK_DEFERRABLE(&info->monitor, exynos4_poll_cur_temp); queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->monitor_period); #endif INIT_DELAYED_WORK_DEFERRABLE(&info->polling, exynos4_handler_tmu_state); info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal %d\n", info->irq); ret = -EINVAL; goto err_irq; } if (soc_is_exynos4210()) ret = request_irq(info->irq, exynos4210_tmu_irq_handler, IRQF_DISABLED, "s5p-tmu interrupt", info); else ret = request_irq(info->irq, exynos4x12_tmu_irq_handler, IRQF_DISABLED, "s5p-tmu interrupt", info); if (ret) { dev_err(&pdev->dev, "request_irq is failed. %d\n", ret); goto err_irq; } ret = tmu_initialize(pdev); if (ret) goto err_init; #ifdef CONFIG_TMU_SYSFS ret = device_create_file(&pdev->dev, &dev_attr_curr_temp); if (ret < 0) { dev_err(&pdev->dev, "Failed to create sysfs group\n"); goto err_init; } #endif #ifdef CONFIG_TMU_DEBUG ret = device_create_file(&pdev->dev, &dev_attr_print_state); if (ret) { dev_err(&pdev->dev, "Failed to create tmu sysfs group\n\n"); return ret; } #endif return ret; err_init: if (info->irq >= 0) free_irq(info->irq, info); err_irq: iounmap(info->tmu_base); err_nomap: release_resource(info->ioarea); kfree(info->ioarea); err_nores: kfree(info); info = NULL; err_nomem: dev_err(&pdev->dev, "initialization failed.\n"); return ret; }
static int __devinit charger_probe(struct platform_device *pdev) { struct twl4030_charger_platform_data *pdata = pdev->dev.platform_data; struct charger_info *di; struct device *dev = &pdev->dev; int irq = -1; int ret; dev_warn(dev, "enter\n"); if (!pdata) { dev_dbg(dev, "platform_data not available\n"); return -EINVAL; } if (!pdata->supplied_to || pdata->num_supplicants < 1) { dev_err(dev, "a supplicant must be sepcified; " "supplied_to=%p num=%zu\n", pdata->supplied_to, pdata->num_supplicants); return -EINVAL; } di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; platform_set_drvdata(pdev, di); di->dev = &pdev->dev; di->recharge_capacity = 94; di->monitor_interval_jiffies = 15 * HZ; di->usb.name = "twl6030_usb"; di->usb.type = POWER_SUPPLY_TYPE_USB; di->usb.properties = charger_usb_props; di->usb.num_properties = ARRAY_SIZE(charger_usb_props); di->usb.get_property = charger_usb_get_property; di->usb.supplied_to = pdata->supplied_to; di->usb.num_supplicants = pdata->num_supplicants; if (pdata->num_supplicants > 1) { dev_warn(dev, "more than one supplicant specified (%zu), only the " "first will be used\n", pdata->num_supplicants); } wake_lock_init(&di->wake_lock, WAKE_LOCK_SUSPEND, "charger_wake_lock"); mutex_init(&di->mutex); di->wq = create_freezable_workqueue(dev_name(di->dev)); INIT_WORK(&di->work, charger_work); setup_timer(&di->timer, charger_timer, (unsigned long) di); /* see if the bootloader already set and locked the limits */ if (charger_is_volimit_locked() == 1) { /* read the vo and vi reg limits set in the bootloader */ di->charger_voltage_mV = charger_get_volimit_config(); di->charger_outcurrent_mA = charger_get_vilimit_config(); dev_warn(&pdev->dev, "Using limits set by bootloader: %d mV %d mA\n", di->charger_voltage_mV, di->charger_outcurrent_mA); } else { /* use the conservative platform data defaults for safety */ di->charger_voltage_mV = pdata->max_bat_voltage_mV; di->charger_outcurrent_mA = pdata->max_charger_current_mA; charger_config_limit1_reg(di, pdata->max_charger_voltage_mV); charger_config_limit2_reg(di, pdata->max_charger_current_mA); dev_warn(&pdev->dev, "Using default limits: %d mV %d mA\n", di->charger_voltage_mV, di->charger_outcurrent_mA); } di->current_limit_mA = 500; ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MBAT_TEMP, CONTROLLER_INT_MASK); if (ret) goto init_failed; ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MASK_MCHARGERUSB_THMREG | MASK_MCURRENT_TERM, CHARGERUSB_INT_MASK); if (ret) goto init_failed; /* setup the initial watchdog state */ di->watchdog_duration = 32; charger_pet_watchdog(di); ret = power_supply_register(dev, &di->usb); if (ret) { dev_err(dev, "failed to register usb power supply\n"); goto usb_failed; } /* get the current supply type, which may have been determined before * the notifier below has been registered */ ret = twl6030_usb_get_supply_type(); if (ret > 0) { dev_info(dev, "initial power supply type is %d\n", ret); di->charger_supply_type = ret; } di->notifier.notifier_call = charger_usb_notifier_call; ret = twl6030_usb_register_notifier(&di->notifier); if (ret) dev_err(dev, "twl6030_usb_register_notifier failed %d\n", ret); /* request charger fault interrupt */ irq = platform_get_irq(pdev, 1); ret = request_threaded_irq(irq, NULL, charger_fault_interrupt, 0, "twl_charger_fault", di); if (ret) { dev_err(dev, "could not request irq %d, status %d\n", irq, ret); goto init_failed; } /* request charger ctrl interrupt */ irq = platform_get_irq(pdev, 0); ret = request_threaded_irq(irq, NULL, charger_ctrl_interrupt, 0, "twl_charger_ctrl", di); if (ret) { dev_err(dev, "could not request irq %d, status %d\n", irq, ret); goto chg_irq_fail; } di->sdev.name = "invalid_charger"; ret = switch_dev_register(&di->sdev); if (ret) { dev_err(di->dev, "error registering switch device: %d\n", ret); goto chg_irq_fail; } ret = sysfs_create_group(&dev->kobj, &charger_charger_attr_group); if (ret) dev_err(dev, "could not create sysfs files\n"); /* setup the led state */ di->led = twl6030_init_led_state(di->dev); if (!di->led) { dev_err(dev, "failed to alloc led state\n"); goto chg_irq_fail; } /* kick ctrl isr to get initial state */ charger_ctrl_interrupt(0, di); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_STS_C); charger_update_state(di); dev_warn(dev, "exit\n"); return 0; /* TODO: fix fail exit mess */ chg_irq_fail: irq = platform_get_irq(pdev, 1); free_irq(irq, di); init_failed: power_supply_unregister(&di->usb); usb_failed: if (irq != -1) free_irq(irq, di); wake_lock_destroy(&di->wake_lock); platform_set_drvdata(pdev, NULL); kfree(di); dev_warn(di->dev, "exit with error: %d\n", ret); return ret; }
static int instinctq_battery_probe(struct platform_device *pdev) { struct s3c_adc_client *client; struct instinctq_battery_pdata *pdata = pdev->dev.platform_data; struct instinctq_battery *bat; int ret, i, irq; /* Platform data is required */ if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; } /* Check GPIOs */ if (!gpio_is_valid(pdata->gpio_pok)) { dev_err(&pdev->dev, "Invalid gpio pin for POK line\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_chg)) { dev_err(&pdev->dev, "Invalid gpio pin for CHG line\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_en)) { dev_err(&pdev->dev, "Invalid gpio pin for EN line\n"); return -EINVAL; } if (!pdata->supply_detect_init) { dev_err(&pdev->dev, "Supply detection is required\n"); return -EINVAL; } /* Register ADC client */ client = s3c_adc_register(pdev, NULL, NULL, 0); if (IS_ERR(client)) { dev_err(&pdev->dev, "could not register adc\n"); return PTR_ERR(client); } /* Allocate driver data */ bat = kzalloc(sizeof(struct instinctq_battery), GFP_KERNEL); if (!bat) { dev_err(&pdev->dev, "could not allocate driver data\n"); ret = -ENOMEM; goto err_free_adc; } /* Claim and setup GPIOs */ ret = gpio_request(pdata->gpio_pok, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request POK pin: %d\n", ret); goto err_free; } ret = gpio_direction_input(pdata->gpio_pok); if (ret) { dev_err(&pdev->dev, "Failed to set POK to input: %d\n", ret); goto err_gpio_pok_free; } ret = gpio_request(pdata->gpio_chg, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request CHG pin: %d\n", ret); goto err_gpio_pok_free; } ret = gpio_direction_input(pdata->gpio_chg); if (ret) { dev_err(&pdev->dev, "Failed to set CHG to input: %d\n", ret); goto err_gpio_chg_free; } ret = gpio_request(pdata->gpio_en, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request EN pin: %d\n", ret); goto err_gpio_chg_free; } ret = gpio_direction_output(pdata->gpio_en, pdata->gpio_en_inverted); if (ret) { dev_err(&pdev->dev, "Failed to set EN to output: %d\n", ret); goto err_gpio_en_free; } platform_set_drvdata(pdev, bat); bat->dev = &pdev->dev; bat->client = client; bat->pdata = pdata; bat->status = POWER_SUPPLY_STATUS_DISCHARGING; bat->health = POWER_SUPPLY_HEALTH_GOOD; bat->supply = instinctq_BATTERY_NONE; bat->interval = BAT_POLL_INTERVAL; bat->calibration = pdata->calibration; ret = create_lookup_table(pdata->percent_lut, pdata->percent_lut_cnt, &bat->percent_lookup); if (ret) { dev_err(&pdev->dev, "could not get create percentage lookup table"); goto err_gpio_en_free; } ret = create_lookup_table(pdata->volt_lut, pdata->volt_lut_cnt, &bat->volt_lookup); if (ret) { dev_err(&pdev->dev, "could not get create voltage lookup table"); goto err_percent_free; } ret = create_lookup_table(pdata->temp_lut, pdata->temp_lut_cnt, &bat->temp_lookup); if (ret) { dev_err(&pdev->dev, "could not get create temperature lookup table"); goto err_volt_free; } INIT_WORK(&bat->work, instinctq_battery_work); INIT_DELAYED_WORK(&bat->poll_work, instinctq_battery_poll); mutex_init(&bat->mutex); #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&bat->wakelock, WAKE_LOCK_SUSPEND, "battery"); wake_lock_init(&bat->chg_wakelock, WAKE_LOCK_SUSPEND, "charger"); wake_lock_init(&bat->fault_wakelock, WAKE_LOCK_SUSPEND, "battery fault"); wake_lock_init(&bat->suspend_lock, WAKE_LOCK_SUSPEND, "suspend_lock"); #endif #ifdef CONFIG_RTC_INTF_ALARM alarm_init(&bat->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, instinctq_battery_alarm); #endif /* Get some initial data for averaging */ for (i = 0; i < NUM_SAMPLES; ++i) { int sample; /* Get a voltage sample from the ADC */ sample = instinctq_battery_adc_read(bat->client, bat->pdata->volt_channel); if (sample < 0) { dev_warn(&pdev->dev, "Failed to get ADC sample.\n"); continue; } sample += bat->compensation; bat->vol_adc = sample; /* Put the sample and get the new average */ bat->volt_value = put_sample_get_avg(&bat->volt_avg, sample); /* Get a temperature sample from the ADC */ sample = instinctq_battery_adc_read(bat->client, bat->pdata->temp_channel); if (sample < 0) { dev_warn(&pdev->dev, "Failed to get ADC sample.\n"); continue; } bat->temp_adc = sample; /* Put the sample and get the new average */ bat->temp_value = put_sample_get_avg(&bat->temp_avg, sample); } bat->percent_value = lookup_value(&bat->percent_lookup, bat->volt_value); bat->volt_value = lookup_value(&bat->volt_lookup, bat->volt_value); bat->temp_value = lookup_value(&bat->temp_lookup, bat->temp_value); bat->last_sample = ktime_get_boottime(); /* Register the power supplies */ for (i = 0; i < instinctq_BATTERY_NUM; ++i) { bat->psy[i] = instinctq_chg_templates[i]; ret = power_supply_register(&pdev->dev, &bat->psy[i]); if (ret < 0) { dev_err(&pdev->dev, "Failed to register power supply %s (%d)\n", bat->psy[i].name, ret); break; } } /* Undo the loop on error */ if (i-- != instinctq_BATTERY_NUM) { for (; i >= 0; --i) power_supply_unregister(&bat->psy[i]); goto err_temp_free; } #ifdef CONFIG_HAS_WAKELOCK ret = device_create_file(bat->psy[instinctq_BATTERY_AC].dev, &dev_attr_suspend_lock); if (ret < 0) { dev_err(&pdev->dev, "Failed to register device attribute.\n"); goto err_psy_unreg; } #endif /* Register the battery */ bat->bat = instinctq_bat_template; ret = power_supply_register(&pdev->dev, &bat->bat); if (ret < 0) { dev_err(&pdev->dev, "Failed to register battery power supply: %d\n", ret); goto err_attr_unreg; } for (i = 0; i < ARRAY_SIZE(battery_attrs); ++i) { ret = device_create_file(bat->bat.dev, battery_attrs[i]); if (ret < 0) break; } if (ret < 0) { for (; i >= 0; --i) device_remove_file(bat->bat.dev, battery_attrs[i]); goto err_bat_unreg; } bat->workqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!bat->workqueue) { dev_err(&pdev->dev, "Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_remove_bat_attr; } /* Claim IRQs */ irq = gpio_to_irq(pdata->gpio_pok); if (irq <= 0) { dev_err(&pdev->dev, "POK irq invalid.\n"); goto err_destroy_workqueue; } bat->irq_pok = irq; ret = request_irq(irq, instinctq_charger_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), bat); if (ret) { dev_err(&pdev->dev, "Failed to request POK irq (%d)\n", ret); goto err_destroy_workqueue; } ret = request_irq(IRQ_BATF, instinctq_battery_fault_irq, 0, dev_name(&pdev->dev), bat); if (ret) { dev_err(&pdev->dev, "Failed to request battery fault irq (%d)\n", ret); goto err_pok_irq_free; } enable_irq_wake(bat->irq_pok); instinctq_battery_set_fault_enable(1); /* Finish */ dev_info(&pdev->dev, "successfully loaded\n"); device_init_wakeup(&pdev->dev, 1); pdata->supply_detect_init(instinctq_battery_supply_notify); /* Schedule work to check current status */ #ifdef CONFIG_HAS_WAKELOCK wake_lock(&bat->wakelock); #endif queue_work(bat->workqueue, &bat->work); return 0; err_pok_irq_free: free_irq(bat->irq_pok, bat); err_destroy_workqueue: destroy_workqueue(bat->workqueue); err_remove_bat_attr: for (i = 0; i < ARRAY_SIZE(battery_attrs); ++i) device_remove_file(bat->bat.dev, battery_attrs[i]); err_bat_unreg: power_supply_unregister(&bat->bat); err_attr_unreg: #ifdef CONFIG_HAS_WAKELOCK device_remove_file(bat->psy[instinctq_BATTERY_AC].dev, &dev_attr_suspend_lock); err_psy_unreg: #endif for (i = 0; i < instinctq_BATTERY_NUM; ++i) power_supply_unregister(&bat->psy[i]); err_temp_free: #ifdef CONFIG_HAS_WAKELOCK wake_lock_destroy(&bat->wakelock); wake_lock_destroy(&bat->chg_wakelock); wake_lock_destroy(&bat->fault_wakelock); wake_lock_destroy(&bat->suspend_lock); #endif kfree(bat->temp_lookup.table); err_volt_free: kfree(bat->volt_lookup.table); err_percent_free: kfree(bat->percent_lookup.table); err_gpio_en_free: gpio_free(pdata->gpio_en); err_gpio_chg_free: gpio_free(pdata->gpio_chg); err_gpio_pok_free: gpio_free(pdata->gpio_pok); err_free: kfree(bat); err_free_adc: s3c_adc_release(client); return ret; }
static int hkdk_tmu_probe(struct platform_device *pdev) { int ret, ret2; struct resource *res; struct s_hkdk_tmu *hkdk_tmu; pr_emerg("HKDK TMU: Loaded\n"); hkdk_tmu = kzalloc(sizeof(struct s_hkdk_tmu), GFP_KERNEL); if (!hkdk_tmu) { pr_emerg("HKDK TMU: Failed to alloc memory to the structure\n"); return -ENOMEM; } hkdk_tmu->dev = &pdev->dev; pr_emerg("HKDK TMU: Pdev\n"); hkdk_tmu->efuse_value = 55; hkdk_tmu->slope = 0x10008802; hkdk_tmu->mode = 0; hkdk_tmu->te1 = 55; hkdk_tmu->TMU_TEMP1 = false; hkdk_tmu->TMU_TEMP2 = false; hkdk_tmu->curr_temp = 10; hkdk_tmu->tmu_state = 0; pr_emerg("HKDK TMU: MAX CPU Frequency: %s", TMU_MAX_FREQ); pr_emerg("HKDK TMU: Set TMU Status\n"); hkdk_tmu->irq = platform_get_irq(pdev, 0); pr_emerg("HKDK TMU: Got IRQ"); if (hkdk_tmu->irq < 0) { pr_emerg("HKDK TMU: No IRQ for TMU -> tmu irq: %d\n", hkdk_tmu->irq); return -ENOMEM; } ret = request_irq(hkdk_tmu->irq, tmu_irq, IRQF_DISABLED, "tmu interrupt", hkdk_tmu); pr_emerg("HKDK TMU: Request IRQ\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL ) { pr_emerg("HKDK TMU: Failed to get memory resources\n"); return -ENOENT; } hkdk_tmu->ioarea = request_mem_region(res->start, res->end-res->start+1, pdev->name); pr_emerg("HKDK TMU: Request IO Memory\n"); if (!(hkdk_tmu->ioarea)) pr_emerg("HKDK TMU: Something wrong at requesting the memory region\n"); hkdk_tmu->tmu_base = ioremap(res->start, (res->end - res->start) + 1); pr_emerg("HKDK TMU: Remap IO Memory\n"); if (!(hkdk_tmu->tmu_base)) pr_emerg("HKDK TMU: Something wrong at the io remap\n"); platform_set_drvdata(pdev, hkdk_tmu); ret2 = device_create_file(&pdev->dev, &dev_attr_curr_temp); hkdk_tmu_initialize(pdev); pr_emerg("HKDK TMU: Initialized\n"); tmu_wq = create_freezable_workqueue("hkdk_tmu_wq"); pr_emerg("HKDK TMU: Created Queue\n"); INIT_DELAYED_WORK_DEFERRABLE(&hkdk_tmu->tmu_work, tmu_work_out); pr_emerg("HKDK TMU: INIT Queue\n"); queue_delayed_work_on(0, tmu_wq, &hkdk_tmu->tmu_work, usecs_to_jiffies(1500 * 1000)); pr_emerg("HKDK TMU: Delay Work created on the queue\n"); return 0; }
static int __devinit twl6030_bci_battery_probe(struct platform_device *pdev) { struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; struct twl6030_bci_device_info *di; int irq = -1; int ret; int i; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); return -EINVAL; } di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; di->platform_data = kmemdup(pdata, sizeof(*pdata), GFP_KERNEL); if (!di->platform_data) { kfree(di); return -ENOMEM; } di->state = STATE_BATTERY; di->monitoring_interval = 15; di->capacity_max_uAh = 570000; di->full_jiffies = msecs_to_jiffies(120 * 1000) + jiffies; di->vbat_jiffies = jiffies; di->dev = &pdev->dev; di->bat.name = "twl6030_battery"; di->bat.supplied_to = twl6030_bci_supplied_to; di->bat.num_supplicants = ARRAY_SIZE(twl6030_bci_supplied_to); di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = twl6030_bci_battery_props; di->bat.num_properties = ARRAY_SIZE(twl6030_bci_battery_props); di->bat.get_property = twl6030_bci_battery_get_property; di->bat_health = POWER_SUPPLY_HEALTH_GOOD; di->usb.name = "twl6030_usb"; di->usb.type = POWER_SUPPLY_TYPE_USB; di->usb.properties = twl6030_usb_props; di->usb.num_properties = ARRAY_SIZE(twl6030_usb_props); di->usb.get_property = twl6030_usb_get_property; platform_set_drvdata(pdev, di); wake_lock_init(&usb_wake_lock, WAKE_LOCK_SUSPEND, "usb_wake_lock"); wake_lock_init(&battery_wake_lock, WAKE_LOCK_SUSPEND, "battery_wake_lock"); di->wq = create_freezable_workqueue(dev_name(&pdev->dev)); /* settings for temperature sensing */ ret = twl6030battery_temp_setup(true); if (ret) goto temp_setup_fail; ret = power_supply_register(&pdev->dev, &di->bat); if (ret) { dev_err(&pdev->dev, "failed to register main battery\n"); goto batt_failed; } ret = power_supply_register(&pdev->dev, &di->usb); if (ret) { dev_err(&pdev->dev, "failed to register usb power supply\n"); goto usb_failed; } di->charge_n1 = 0; di->timer_n1 = 0; INIT_WORK(&di->charge_control_work, twl6030_charge_control_work); INIT_WORK(&di->charge_fault_work, twl6030_charge_fault_work); INIT_WORK(&di->calibration_work, twl6030_calibration_work); INIT_DELAYED_WORK_DEFERRABLE(&di->monitor_work, twl6030_monitor_work); ret = twl6030battery_voltage_setup(di); if (ret) dev_err(&pdev->dev, "voltage measurement setup failed\n"); ret = twl6030battery_current_setup(true); if (ret) dev_err(&pdev->dev, "current measurement setup failed\n"); /* initialize for USB charging */ twl6030_config_limit1_reg(di, pdata->max_charger_voltagemV); twl6030_config_limit2_reg(di, pdata->max_charger_currentmA); ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MBAT_TEMP, CONTROLLER_INT_MASK); if (ret) goto init_failed; ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MASK_MCHARGERUSB_THMREG | MASK_MCURRENT_TERM, CHARGERUSB_INT_MASK); if (ret) goto init_failed; di->charger_outcurrentmA = di->platform_data->max_charger_currentmA; twl6030_set_watchdog(di, 32); di->nb.notifier_call = twl6030_usb_notifier_call; di->otg = otg_get_transceiver(); if (di->otg) { ret = otg_register_notifier(di->otg, &di->nb); if (ret) dev_err(&pdev->dev, "otg register notifier failed %d\n", ret); } else dev_err(&pdev->dev, "otg_get_transceiver failed %d\n", ret); di->charger_incurrentmA = twl6030_get_usb_max_power(di->otg); di->gpadc_vbat_chnl = TWL6030_GPADC_VBAT_CHNL; di->voltage_mV = twl6030_get_gpadc_conversion(di, di->gpadc_vbat_chnl); dev_info(&pdev->dev, "Battery Voltage at Bootup is %d mV\n", di->voltage_mV); /* initialize the voltage history table */ /* TODO: consider the best initial values for the table */ for (i=0; i < VOLTAGE_HISTORY_LENGTH; i++) di->voltage_history[i] = di->voltage_mV; /* start with a rough estimate */ di->capacity = twl6030_estimate_capacity(di); if (di->capacity < 5) di->capacity = 5; if (di->capacity > 50) di->capacity = 50; ret = twl6030backupbatt_setup(); if (ret) dev_err(&pdev->dev, "Backup Bat charging setup failed\n"); /* request charger fault interruption */ irq = platform_get_irq(pdev, 1); ret = request_threaded_irq(irq, NULL, twl6030charger_fault_interrupt, 0, "twl_bci_fault", di); if (ret) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto init_failed; } /* request charger ctrl interruption */ irq = platform_get_irq(pdev, 0); ret = request_threaded_irq(irq, NULL, twl6030charger_ctrl_interrupt, 0, "twl_bci_ctrl", di); if (ret) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto chg_irq_fail; } twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_STS_C); ret = sysfs_create_group(&pdev->dev.kobj, &twl6030_bci_attr_group); if (ret) dev_err(&pdev->dev, "could not create sysfs files\n"); queue_work(di->wq, &di->calibration_work); queue_delayed_work(di->wq, &di->monitor_work, 0); return 0; /* TODO: fix fail exit mess */ chg_irq_fail: irq = platform_get_irq(pdev, 1); free_irq(irq, di); init_failed: power_supply_unregister(&di->usb); usb_failed: power_supply_unregister(&di->bat); batt_failed: if (irq != -1) free_irq(irq, di); temp_setup_fail: wake_lock_destroy(&usb_wake_lock); platform_set_drvdata(pdev, NULL); kfree(di); return ret; }
static irqreturn_t tmu_irq(int irq, void *id) { struct tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + INTSTAT); /* To handle multiple interrupt pending, * interrupt by high temperature are serviced with priority. */ #if defined(CONFIG_TC_VOLTAGE) if (status & INTSTAT_FALL0) { pr_info("TC interrupt occured..!\n"); __raw_writel(INTCLEAR_FALL0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_TC; } else if (status & INTSTAT_RISE2) { #else if (status & INTSTAT_RISE2) { #endif pr_info("Tripping interrupt occured..!\n"); info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR_RISE2, info->tmu_base + INTCLEAR); } else if (status & INTSTAT_RISE1) { pr_info("Warning interrupt occured..!\n"); __raw_writel(INTCLEAR_RISE1, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_WARNING; } else if (status & INTSTAT_RISE0) { pr_info("Throttling interrupt occured..!\n"); __raw_writel(INTCLEAR_RISE0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_THROTTLED; } else { pr_err("%s: TMU interrupt error\n", __func__); return -ENODEV; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1 * 1000)); return IRQ_HANDLED; } static irqreturn_t exynos4210_tmu_irq(int irq, void *id) { struct tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + INTSTAT); if (status & INTSTAT2) { pr_info("Tripping interrupt occured..!\n"); info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR2, info->tmu_base + INTCLEAR); } else if (status & INTSTAT1) { pr_info("Warning interrupt occured..!\n"); __raw_writel(INTCLEAR1, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_WARNING; } else if (status & INTSTAT0) { pr_info("Throttling interrupt occured..!\n"); __raw_writel(INTCLEAR0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_THROTTLED; } else { pr_err("%s: TMU interrupt error\n", __func__); return -ENODEV; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1000)); return IRQ_HANDLED; } static int __devinit tmu_probe(struct platform_device *pdev) { struct tmu_info *info; struct resource *res; int ret = 0; pr_debug("%s: probe=%p\n", __func__, pdev); info = kzalloc(sizeof(struct tmu_info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_nomem; } pr_emerg("TMU: Memory Allocation Sucessful\n"); platform_set_drvdata(pdev, info); pr_emerg("TMU: Platform data set\n"); info->dev = &pdev->dev; pr_emerg("TMU: Copied the Dev access Information \n"); info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal\n"); ret = -ENOENT; goto err_noirq; } if (soc_is_exynos4210()) ret = request_irq(info->irq, exynos4210_tmu_irq, IRQF_DISABLED, "tmu interrupt", info); else ret = request_irq(info->irq, tmu_irq, IRQF_DISABLED, "tmu interrupt", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq, ret); goto err_noirq; } pr_emerg("TMU: IRQ Granted!\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get memory region resource\n"); ret = -ENODEV; goto err_nores; } pr_emerg("TMU: IO Resource alloced on Memory\n"); info->ioarea = request_mem_region(res->start, res->end-res->start+1, pdev->name); if (!(info->ioarea)) { dev_err(&pdev->dev, "failed to reserve memory region\n"); ret = -EBUSY; goto err_nores; } pr_emerg("TMU: Memory area resersed\n"); info->tmu_base = ioremap(res->start, (res->end - res->start) + 1); if (!(info->tmu_base)) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -EINVAL; goto err_nomap; } pr_emerg("TMU: IO Memory Remapped\n"); if (thermal_create_sysfs_file(&pdev->dev)) goto err_sysfs; pr_emerg("TMU: Created Sysfs\n"); tmu_monitor_wq = create_freezable_workqueue("tmu"); if (!tmu_monitor_wq) { dev_err(&pdev->dev, "Creation of tmu_monitor_wq failed\n"); ret = -EFAULT; goto err_wq; } pr_emerg("TMU: Workqueue Created\n"); INIT_DELAYED_WORK_DEFERRABLE(&info->polling, tmu_monitor); pr_emerg("TMU: Work Created\n"); #ifdef CONFIG_TMU_DEBUG INIT_DELAYED_WORK_DEFERRABLE(&info->monitor, cur_temp_monitor); #endif print_temperature_params(info); pr_emerg("TMU: Printed Parameters\n"); ret = tmu_initialize(pdev); if (ret < 0) goto err_noinit; #ifdef CONFIG_TMU_DEBUG queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->sampling_rate); #endif pr_info("Tmu Initialization is sucessful...!\n"); return ret; err_noinit: destroy_workqueue(tmu_monitor_wq); err_wq: thermal_remove_sysfs_file(&pdev->dev); err_sysfs: iounmap(info->tmu_base); err_nomap: release_resource(info->ioarea); err_nores: free_irq(info->irq, info); err_noirq: kfree(info); info = NULL; err_nomem: dev_err(&pdev->dev, "initialization failed.\n"); return ret; } static int __devinit tmu_remove(struct platform_device *pdev) { struct tmu_info *info = platform_get_drvdata(pdev); cancel_delayed_work(&info->polling); destroy_workqueue(tmu_monitor_wq); thermal_remove_sysfs_file(&pdev->dev); iounmap(info->tmu_base); release_resource(info->ioarea); free_irq(info->irq, (void *)pdev); kfree(info); info = NULL; pr_info("%s is removed\n", dev_name(&pdev->dev)); return 0; } #ifdef CONFIG_PM static int tmu_suspend(struct platform_device *pdev, pm_message_t state) { struct tmu_info *info = platform_get_drvdata(pdev); pm_tmu_save(info); return 0; } static int tmu_resume(struct platform_device *pdev) { struct tmu_info *info = platform_get_drvdata(pdev); #if defined(CONFIG_TC_VOLTAGE) struct tmu_data *data = info->dev->platform_data; #endif pm_tmu_restore(info); #if defined(CONFIG_TC_VOLTAGE) /* s/w workaround for fast service when interrupt is not occured, * such as current temp is lower than tc interrupt temperature * or current temp is continuosly increased. */ mdelay(1); if (get_cur_temp(info) <= data->ts.start_tc) { disable_irq_nosync(info->irq); if (exynos_tc_volt(info, 1) < 0) pr_err("%s\n", __func__); info->tmu_state = TMU_STATUS_TC; already_limit = 1; queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1 * 1000)); } #endif return 0; } #else #define tmu_suspend NULL #define tmu_resume NULL #endif static struct platform_driver tmu_driver = { .probe = tmu_probe, .remove = tmu_remove, .suspend = tmu_suspend, .resume = tmu_resume, .driver = { .name = "tmu", .owner = THIS_MODULE, }, }; static int __init tmu_driver_init(void) { return platform_driver_register(&tmu_driver); } late_initcall(tmu_driver_init);
static int __devinit tmu_probe(struct platform_device *pdev) { struct tmu_info *info; struct resource *res; int ret = 0; pr_debug("%s: probe=%p\n", __func__, pdev); info = kzalloc(sizeof(struct tmu_info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_nores; } platform_set_drvdata(pdev, info); info->dev = &pdev->dev; info->tmu_state = TMU_STATUS_INIT; info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal\n"); return -ENOENT; } ret = request_irq(info->irq, tmu_irq, IRQF_DISABLED, "tmu interrupt", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq, ret); goto err_noirq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get memory region resource\n"); return -ENOENT; } info->ioarea = request_mem_region(res->start, res->end-res->start+1, pdev->name); if (!(info->ioarea)) { dev_err(&pdev->dev, "failed to reserve memory region\n"); ret = -ENOENT; goto err_nores; } info->tmu_base = ioremap(res->start, (res->end - res->start) + 1); if (!(info->tmu_base)) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -EINVAL; goto err_nomap; } tmu_monitor_wq = create_freezable_workqueue("tmu"); if (!tmu_monitor_wq) { pr_info("Creation of tmu_monitor_wq failed\n"); return -EFAULT; } #ifdef CONFIG_TMU_DEBUG INIT_DELAYED_WORK_DEFERRABLE(&info->monitor, cur_temp_monitor); queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, usecs_to_jiffies(1000 * 1000)); #endif INIT_DELAYED_WORK_DEFERRABLE(&info->polling, tmu_monitor); ret = tmu_initialize(pdev); if (ret) goto err_noinit; return ret; err_noinit: free_irq(info->irq, info); err_noirq: iounmap(info->tmu_base); err_nomap: release_resource(info->ioarea); err_nores: return ret; }