int ath10k_thermal_register(struct ath10k *ar) { struct thermal_cooling_device *cdev; struct device *hwmon_dev; int ret; if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) return 0; cdev = thermal_cooling_device_register("ath10k_thermal", ar, &ath10k_thermal_ops); if (IS_ERR(cdev)) { ath10k_err(ar, "failed to setup thermal device result: %ld\n", PTR_ERR(cdev)); return -EINVAL; } ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj, "cooling_device"); if (ret) { ath10k_err(ar, "failed to create cooling device symlink\n"); goto err_cooling_destroy; } ar->thermal.cdev = cdev; ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT; /* Do not register hwmon device when temperature reading is not * supported by firmware */ if (!(ar->wmi.ops->gen_pdev_get_temperature)) return 0; /* Avoid linking error on devm_hwmon_device_register_with_groups, I * guess linux/hwmon.h is missing proper stubs. */ if (!IS_REACHABLE(CONFIG_HWMON)) return 0; hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, "ath10k_hwmon", ar, ath10k_hwmon_groups); if (IS_ERR(hwmon_dev)) { ath10k_err(ar, "failed to register hwmon device: %ld\n", PTR_ERR(hwmon_dev)); ret = -EINVAL; goto err_remove_link; } return 0; err_remove_link: sysfs_remove_link(&ar->dev->kobj, "cooling_device"); err_cooling_destroy: thermal_cooling_device_unregister(cdev); return ret; }
static int exynos_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct exynos_adc *info = iio_priv(indio_dev); if (IS_REACHABLE(CONFIG_INPUT) && info->input) { free_irq(info->tsirq, info); input_unregister_device(info->input); } device_for_each_child(&indio_dev->dev, NULL, exynos_adc_remove_devices); iio_device_unregister(indio_dev); free_irq(info->irq, info); if (info->data->exit_hw) info->data->exit_hw(info); exynos_adc_disable_clk(info); exynos_adc_unprepare_clk(info); regulator_disable(info->vdd); return 0; }
/* Clear all weakrefs to unreachable objects, and if such a weakref has a * callback, invoke it if necessary. Note that it's possible for such * weakrefs to be outside the unreachable set -- indeed, those are precisely * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for * overview & some details. Some weakrefs with callbacks may be reclaimed * directly by this routine; the number reclaimed is the return value. Other * weakrefs with callbacks may be moved into the `old` generation. Objects * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, * no object in `unreachable` is weakly referenced anymore. */ static int handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) { PyGC_Head *gc; PyObject *op; /* generally FROM_GC(gc) */ PyWeakReference *wr; /* generally a cast of op */ PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ PyGC_Head *next; int num_freed = 0; gc_list_init(&wrcb_to_call); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback * needs to be invoked. Note that we cannot invoke any callbacks until * all weakrefs to unreachable objects are cleared, lest the callback * resurrect an unreachable object via a still-active weakref. We * make another pass over wrcb_to_call, invoking callbacks, after this * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); next = gc->gc.gc_next; if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) continue; /* It supports weakrefs. Does it have any? */ wrlist = (PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(op); /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ /* _PyWeakref_ClearRef clears the weakref but leaves * the callback pointer intact. Obscure: it also * changes *wrlist. */ assert(wr->wr_object == op); _PyWeakref_ClearRef(wr); assert(wr->wr_object == Py_None); if (wr->wr_callback == NULL) continue; /* no callback */ /* Headache time. `op` is going away, and is weakly referenced by * `wr`, which has a callback. Should the callback be invoked? If wr * is also trash, no: * * 1. There's no need to call it. The object and the weakref are * both going away, so it's legitimate to pretend the weakref is * going away first. The user has to ensure a weakref outlives its * referent if they want a guarantee that the wr callback will get * invoked. * * 2. It may be catastrophic to call it. If the callback is also in * cyclic trash (CT), then although the CT is unreachable from * outside the current generation, CT may be reachable from the * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, * wr is simply left in the unreachable set. Note that because we * already called _PyWeakref_ClearRef(wr), its callback will never * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this * case, its callback can't be CT either -- wr acted as an external * root to this generation, and therefore its callback did too. So * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. */ if (IS_TENTATIVELY_UNREACHABLE(wr)) continue; assert(IS_REACHABLE(wr)); /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); assert(wrasgc != next); /* wrasgc is reachable, but next isn't, so they can't be the same */ gc_list_move(wrasgc, &wrcb_to_call); } } /* Invoke the callbacks we decided to honor. It's safe to invoke them * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; PyObject *callback; gc = wrcb_to_call.gc.gc_next; op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); wr = (PyWeakReference *)op; callback = wr->wr_callback; assert(callback != NULL); /* copy-paste of weakrefobject.c's handle_callback() */ temp = PyObject_CallFunction(callback, "O", wr); if (temp == NULL) PyErr_WriteUnraisable(callback); else Py_DECREF(temp); /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), * op's tp_dealloc will decref op->wr_callback too. Note * that the refcount probably will hit 0 now, and because this * weakref was reachable to begin with, gc didn't already * add it to its count of freed objects. Example: a reachable * weak value dict maps some key to this reachable weakref. * The callback removes this key->weakref mapping from the * dict, leaving no other references to the weakref (excepting * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_move(gc, old); } else ++num_freed; } return num_freed; }
static int exynos_adc_probe(struct platform_device *pdev) { struct exynos_adc *info = NULL; struct device_node *np = pdev->dev.of_node; struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = NULL; struct resource *mem; bool has_ts = false; int ret = -ENODEV; int irq; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); if (!indio_dev) { dev_err(&pdev->dev, "failed allocating iio device\n"); return -ENOMEM; } info = iio_priv(indio_dev); info->data = exynos_adc_get_data(pdev); if (!info->data) { dev_err(&pdev->dev, "failed getting exynos_adc_data\n"); return -EINVAL; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); info->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); if (info->data->needs_adc_phy) { info->pmu_map = syscon_regmap_lookup_by_phandle( pdev->dev.of_node, "samsung,syscon-phandle"); if (IS_ERR(info->pmu_map)) { dev_err(&pdev->dev, "syscon regmap lookup failed.\n"); return PTR_ERR(info->pmu_map); } } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); return irq; } info->irq = irq; irq = platform_get_irq(pdev, 1); if (irq == -EPROBE_DEFER) return irq; info->tsirq = irq; info->dev = &pdev->dev; init_completion(&info->completion); info->clk = devm_clk_get(&pdev->dev, "adc"); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed getting clock, err = %ld\n", PTR_ERR(info->clk)); return PTR_ERR(info->clk); } if (info->data->needs_sclk) { info->sclk = devm_clk_get(&pdev->dev, "sclk"); if (IS_ERR(info->sclk)) { dev_err(&pdev->dev, "failed getting sclk clock, err = %ld\n", PTR_ERR(info->sclk)); return PTR_ERR(info->sclk); } } info->vdd = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(info->vdd)) { dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", PTR_ERR(info->vdd)); return PTR_ERR(info->vdd); } ret = regulator_enable(info->vdd); if (ret) return ret; ret = exynos_adc_prepare_clk(info); if (ret) goto err_disable_reg; ret = exynos_adc_enable_clk(info); if (ret) goto err_unprepare_clk; platform_set_drvdata(pdev, indio_dev); indio_dev->name = dev_name(&pdev->dev); indio_dev->dev.parent = &pdev->dev; indio_dev->dev.of_node = pdev->dev.of_node; indio_dev->info = &exynos_adc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = exynos_adc_iio_channels; indio_dev->num_channels = info->data->num_channels; ret = request_irq(info->irq, exynos_adc_isr, 0, dev_name(&pdev->dev), info); if (ret < 0) { dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", info->irq); goto err_disable_clk; } ret = iio_device_register(indio_dev); if (ret) goto err_irq; if (info->data->init_hw) info->data->init_hw(info); /* leave out any TS related code if unreachable */ if (IS_REACHABLE(CONFIG_INPUT)) { has_ts = of_property_read_bool(pdev->dev.of_node, "has-touchscreen") || pdata; } if (pdata) info->delay = pdata->delay; else info->delay = 10000; if (has_ts) ret = exynos_adc_ts_init(info); if (ret) goto err_iio; ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); if (ret < 0) { dev_err(&pdev->dev, "failed adding child nodes\n"); goto err_of_populate; } return 0; err_of_populate: device_for_each_child(&indio_dev->dev, NULL, exynos_adc_remove_devices); if (has_ts) { input_unregister_device(info->input); free_irq(info->tsirq, info); } err_iio: iio_device_unregister(indio_dev); err_irq: free_irq(info->irq, info); err_disable_clk: if (info->data->exit_hw) info->data->exit_hw(info); exynos_adc_disable_clk(info); err_unprepare_clk: exynos_adc_unprepare_clk(info); err_disable_reg: regulator_disable(info->vdd); return ret; }