// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h>#include <linux/clk.h>#include <linux/of_clk.h>#include <linux/minmax.h>#include <linux/of_address.h>#include <linux/platform_data/simplefb.h>#include <linux/platform_device.h>#include <linux/pm_domain.h>#include <linux/regulator/consumer.h> #include <drm/clients/drm_client_setup.h>#include <drm/drm_atomic.h>#include <drm/drm_atomic_state_helper.h>#include <drm/drm_connector.h>#include <drm/drm_crtc_helper.h>#include <drm/drm_damage_helper.h>#include <drm/drm_device.h>#include <drm/drm_drv.h>#include <drm/drm_fbdev_shmem.h>#include <drm/drm_format_helper.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_gem_shmem_helper.h>#include <drm/drm_managed.h>#include <drm/drm_modeset_helper_vtables.h>#include <drm/drm_panic.h>#include <drm/drm_probe_helper.h> #define DRIVER_NAME "simpledrm"#define DRIVER_DESC "DRM driver for simple-framebuffer platform devices"#define DRIVER_MAJOR 1#define DRIVER_MINOR 0 /* * Helpers for simplefb */ static intsimplefb_get_validated_int(struct drm_device *dev, const char *name, uint32_t value){ if (value > INT_MAX) { drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", name, value); return -EINVAL; } return (int)value;} static intsimplefb_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value){ if (!value) { drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", name, value); return -EINVAL; } return simplefb_get_validated_int(dev, name, value);} static const struct drm_format_info *simplefb_get_validated_format(struct drm_device *dev, const char *format_name){ static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; const struct simplefb_format *fmt = formats; const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); const struct drm_format_info *info; if (!format_name) { drm_err(dev, "simplefb: missing framebuffer format\n"); return ERR_PTR(-EINVAL); } while (fmt < end) { if (!strcmp(format_name, fmt->name)) { info = drm_format_info(fmt->fourcc); if (!info) return ERR_PTR(-EINVAL); return info; } ++fmt; } drm_err(dev, "simplefb: unknown framebuffer format %s\n", format_name); return ERR_PTR(-EINVAL);} static intsimplefb_get_width_pd(struct drm_device *dev, const struct simplefb_platform_data *pd){ return simplefb_get_validated_int0(dev, "width", pd->width);} static intsimplefb_get_height_pd(struct drm_device *dev, const struct simplefb_platform_data *pd){ return simplefb_get_validated_int0(dev, "height", pd->height);} static intsimplefb_get_stride_pd(struct drm_device *dev, const struct simplefb_platform_data *pd){ return simplefb_get_validated_int(dev, "stride", pd->stride);} static const struct drm_format_info *simplefb_get_format_pd(struct drm_device *dev, const struct simplefb_platform_data *pd){ return simplefb_get_validated_format(dev, pd->format);} static intsimplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, const char *name, u32 *value){ int ret = of_property_read_u32(of_node, name, value); if (ret) drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", name, ret); return ret;} static intsimplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, const char *name, const char **value){ int ret = of_property_read_string(of_node, name, value); if (ret) drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", name, ret); return ret;} static intsimplefb_get_width_of(struct drm_device *dev, struct device_node *of_node){ u32 width; int ret = simplefb_read_u32_of(dev, of_node, "width", &width); if (ret) return ret; return simplefb_get_validated_int0(dev, "width", width);} static intsimplefb_get_height_of(struct drm_device *dev, struct device_node *of_node){ u32 height; int ret = simplefb_read_u32_of(dev, of_node, "height", &height); if (ret) return ret; return simplefb_get_validated_int0(dev, "height", height);} static intsimplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node){ u32 stride; int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); if (ret) return ret; return simplefb_get_validated_int(dev, "stride", stride);} static const struct drm_format_info *simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node){ const char *format; int ret = simplefb_read_string_of(dev, of_node, "format", &format); if (ret) return ERR_PTR(ret); return simplefb_get_validated_format(dev, format);} static struct resource *simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node){ struct device_node *np; struct resource *res; int err; np = of_parse_phandle(of_node, "memory-region", 0); if (!np) return NULL; res = devm_kzalloc(dev->dev, sizeof(*res), GFP_KERNEL); if (!res) return ERR_PTR(-ENOMEM); err = of_address_to_resource(np, 0, res); if (err) return ERR_PTR(err); if (of_property_present(of_node, "reg")) drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n"); return res;} /* * Simple Framebuffer device */ struct simpledrm_device { struct drm_device dev; /* clocks */#if defined CONFIG_OF && defined CONFIG_COMMON_CLK unsigned int clk_count; struct clk **clks;#endif /* regulators */#if defined CONFIG_OF && defined CONFIG_REGULATOR unsigned int regulator_count; struct regulator **regulators;#endif /* power-domains */#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS int pwr_dom_count; struct device **pwr_dom_devs; struct device_link **pwr_dom_links;#endif /* simplefb settings */ struct drm_display_mode mode; const struct drm_format_info *format; unsigned int pitch; /* memory management */ struct iosys_map screen_base; /* modesetting */ uint32_t formats[8]; size_t nformats; struct drm_plane primary_plane; struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector;}; static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev){ return container_of(dev, struct simpledrm_device, dev);} /* * Hardware */ #if defined CONFIG_OF && defined CONFIG_COMMON_CLK/* * Clock handling code. * * Here we handle the clocks property of our "simple-framebuffer" dt node. * This is necessary so that we can make sure that any clocks needed by * the display engine that the bootloader set up for us (and for which it * provided a simplefb dt node), stay up, for the life of the simplefb * driver. * * When the driver unloads, we cleanly disable, and then release the clocks. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the clock definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_clocks(void *res){ struct simpledrm_device *sdev = simpledrm_device_of_dev(res); unsigned int i; for (i = 0; i < sdev->clk_count; ++i) { if (sdev->clks[i]) { clk_disable_unprepare(sdev->clks[i]); clk_put(sdev->clks[i]); } }} static int simpledrm_device_init_clocks(struct simpledrm_device *sdev){ struct drm_device *dev = &sdev->dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct clk *clock; unsigned int i; int ret; if (dev_get_platdata(&pdev->dev) || !of_node) return 0; sdev->clk_count = of_clk_get_parent_count(of_node); if (!sdev->clk_count) return 0; sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]), GFP_KERNEL); if (!sdev->clks) return -ENOMEM; for (i = 0; i < sdev->clk_count; ++i) { clock = of_clk_get(of_node, i); if (IS_ERR(clock)) { ret = PTR_ERR(clock); if (ret == -EPROBE_DEFER) goto err; drm_err(dev, "clock %u not found: %d\n", i, ret); continue; } ret = clk_prepare_enable(clock); if (ret) { drm_err(dev, "failed to enable clock %u: %d\n", i, ret); clk_put(clock); continue; } sdev->clks[i] = clock; } return devm_add_action_or_reset(&pdev->dev, simpledrm_device_release_clocks, sdev); err: while (i) { --i; if (sdev->clks[i]) { clk_disable_unprepare(sdev->clks[i]); clk_put(sdev->clks[i]); } } return ret;}#elsestatic int simpledrm_device_init_clocks(struct simpledrm_device *sdev){ return 0;}#endif #if defined CONFIG_OF && defined CONFIG_REGULATOR #define SUPPLY_SUFFIX "-supply" /* * Regulator handling code. * * Here we handle the num-supplies and vin*-supply properties of our * "simple-framebuffer" dt node. This is necessary so that we can make sure * that any regulators needed by the display hardware that the bootloader * set up for us (and for which it provided a simplefb dt node), stay up, * for the life of the simplefb driver. * * When the driver unloads, we cleanly disable, and then release the * regulators. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the regulator definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_regulators(void *res){ struct simpledrm_device *sdev = simpledrm_device_of_dev(res); unsigned int i; for (i = 0; i < sdev->regulator_count; ++i) { if (sdev->regulators[i]) { regulator_disable(sdev->regulators[i]); regulator_put(sdev->regulators[i]); } }} static int simpledrm_device_init_regulators(struct simpledrm_device *sdev){ struct drm_device *dev = &sdev->dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct property *prop; struct regulator *regulator; const char *p; unsigned int count = 0, i = 0; int ret; if (dev_get_platdata(&pdev->dev) || !of_node) return 0; /* Count the number of regulator supplies */ for_each_property_of_node(of_node, prop) { p = strstr(prop->name, SUPPLY_SUFFIX); if (p && p != prop->name) ++count; } if (!count) return 0; sdev->regulators = drmm_kzalloc(dev, count * sizeof(sdev->regulators[0]), GFP_KERNEL); if (!sdev->regulators) return -ENOMEM; for_each_property_of_node(of_node, prop) { char name[32]; /* 32 is max size of property name */ size_t len; p = strstr(prop->name, SUPPLY_SUFFIX); if (!p || p == prop->name) continue; len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; strscpy(name, prop->name, min(sizeof(name), len)); regulator = regulator_get_optional(&pdev->dev, name); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); if (ret == -EPROBE_DEFER) goto err; drm_err(dev, "regulator %s not found: %d\n", name, ret); continue; } ret = regulator_enable(regulator); if (ret) { drm_err(dev, "failed to enable regulator %u: %d\n", i, ret); regulator_put(regulator); continue; } sdev->regulators[i++] = regulator; } sdev->regulator_count = i; return devm_add_action_or_reset(&pdev->dev, simpledrm_device_release_regulators, sdev); err: while (i) { --i; if (sdev->regulators[i]) { regulator_disable(sdev->regulators[i]); regulator_put(sdev->regulators[i]); } } return ret;}#elsestatic int simpledrm_device_init_regulators(struct simpledrm_device *sdev){ return 0;}#endif #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS/* * Generic power domain handling code. * * Here we handle the power-domains properties of our "simple-framebuffer" * dt node. This is only necessary if there is more than one power-domain. * A single power-domains is handled automatically by the driver core. Multiple * power-domains have to be handled by drivers since the driver core can't know * the correct power sequencing. Power sequencing is not an issue for simpledrm * since the bootloader has put the power domains already in the correct state. * simpledrm has only to ensure they remain active for its lifetime. * * When the driver unloads, we detach from the power-domains. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up the "simple-framebuffer" dt node, and the PM domain providers in the * device tree. Chances are that there are no adverse effects, and if there are, * a clean teardown of the fb probe will not help us much either. So just * complain and carry on, and hope that the user actually gets a working fb at * the end of things. */Lines 1–500 of 1073. Load more
// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h> #include <linux/clk.h> #include <linux/of_clk.h> #include <linux/minmax.h> #include <linux/of_address.h> #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/regulator/consumer.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_connector.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_shmem.h> #include <drm/drm_format_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_panic.h> #include <drm/drm_probe_helper.h> #define DRIVER_NAME "simpledrm" #define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 /* * Helpers for simplefb */ static int simplefb_get_validated_int(struct drm_device *dev, const char *name, uint32_t value) { if (value > INT_MAX) { drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", name, value); return -EINVAL; } return (int)value; } static int simplefb_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value) { if (!value) { drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", name, value); return -EINVAL; } return simplefb_get_validated_int(dev, name, value); } static const struct drm_format_info * simplefb_get_validated_format(struct drm_device *dev, const char *format_name) { static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; const struct simplefb_format *fmt = formats; const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); const struct drm_format_info *info; if (!format_name) { drm_err(dev, "simplefb: missing framebuffer format\n"); return ERR_PTR(-EINVAL); } while (fmt < end) { if (!strcmp(format_name, fmt->name)) { info = drm_format_info(fmt->fourcc); if (!info) return ERR_PTR(-EINVAL); return info; } ++fmt; } drm_err(dev, "simplefb: unknown framebuffer format %s\n", format_name); return ERR_PTR(-EINVAL); } static int simplefb_get_width_pd(struct drm_device *dev, const struct simplefb_platform_data *pd) { return simplefb_get_validated_int0(dev, "width", pd->width); } static int simplefb_get_height_pd(struct drm_device *dev, const struct simplefb_platform_data *pd) { return simplefb_get_validated_int0(dev, "height", pd->height); } static int simplefb_get_stride_pd(struct drm_device *dev, const struct simplefb_platform_data *pd) { return simplefb_get_validated_int(dev, "stride", pd->stride); } static const struct drm_format_info * simplefb_get_format_pd(struct drm_device *dev, const struct simplefb_platform_data *pd) { return simplefb_get_validated_format(dev, pd->format); } static int simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, const char *name, u32 *value) { int ret = of_property_read_u32(of_node, name, value); if (ret) drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", name, ret); return ret; } static int simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, const char *name, const char **value) { int ret = of_property_read_string(of_node, name, value); if (ret) drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", name, ret); return ret; } static int simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node) { u32 width; int ret = simplefb_read_u32_of(dev, of_node, "width", &width); if (ret) return ret; return simplefb_get_validated_int0(dev, "width", width); } static int simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node) { u32 height; int ret = simplefb_read_u32_of(dev, of_node, "height", &height); if (ret) return ret; return simplefb_get_validated_int0(dev, "height", height); } static int simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node) { u32 stride; int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); if (ret) return ret; return simplefb_get_validated_int(dev, "stride", stride); } static const struct drm_format_info * simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) { const char *format; int ret = simplefb_read_string_of(dev, of_node, "format", &format); if (ret) return ERR_PTR(ret); return simplefb_get_validated_format(dev, format); } static struct resource * simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node) { struct device_node *np; struct resource *res; int err; np = of_parse_phandle(of_node, "memory-region", 0); if (!np) return NULL; res = devm_kzalloc(dev->dev, sizeof(*res), GFP_KERNEL); if (!res) return ERR_PTR(-ENOMEM); err = of_address_to_resource(np, 0, res); if (err) return ERR_PTR(err); if (of_property_present(of_node, "reg")) drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n"); return res; } /* * Simple Framebuffer device */ struct simpledrm_device { struct drm_device dev; /* clocks */ #if defined CONFIG_OF && defined CONFIG_COMMON_CLK unsigned int clk_count; struct clk **clks; #endif /* regulators */ #if defined CONFIG_OF && defined CONFIG_REGULATOR unsigned int regulator_count; struct regulator **regulators; #endif /* power-domains */ #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS int pwr_dom_count; struct device **pwr_dom_devs; struct device_link **pwr_dom_links; #endif /* simplefb settings */ struct drm_display_mode mode; const struct drm_format_info *format; unsigned int pitch; /* memory management */ struct iosys_map screen_base; /* modesetting */ uint32_t formats[8]; size_t nformats; struct drm_plane primary_plane; struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector; }; static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) { return container_of(dev, struct simpledrm_device, dev); } /* * Hardware */ #if defined CONFIG_OF && defined CONFIG_COMMON_CLK /* * Clock handling code. * * Here we handle the clocks property of our "simple-framebuffer" dt node. * This is necessary so that we can make sure that any clocks needed by * the display engine that the bootloader set up for us (and for which it * provided a simplefb dt node), stay up, for the life of the simplefb * driver. * * When the driver unloads, we cleanly disable, and then release the clocks. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the clock definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_clocks(void *res) { struct simpledrm_device *sdev = simpledrm_device_of_dev(res); unsigned int i; for (i = 0; i < sdev->clk_count; ++i) { if (sdev->clks[i]) { clk_disable_unprepare(sdev->clks[i]); clk_put(sdev->clks[i]); } } } static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) { struct drm_device *dev = &sdev->dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct clk *clock; unsigned int i; int ret; if (dev_get_platdata(&pdev->dev) || !of_node) return 0; sdev->clk_count = of_clk_get_parent_count(of_node); if (!sdev->clk_count) return 0; sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]), GFP_KERNEL); if (!sdev->clks) return -ENOMEM; for (i = 0; i < sdev->clk_count; ++i) { clock = of_clk_get(of_node, i); if (IS_ERR(clock)) { ret = PTR_ERR(clock); if (ret == -EPROBE_DEFER) goto err; drm_err(dev, "clock %u not found: %d\n", i, ret); continue; } ret = clk_prepare_enable(clock); if (ret) { drm_err(dev, "failed to enable clock %u: %d\n", i, ret); clk_put(clock); continue; } sdev->clks[i] = clock; } return devm_add_action_or_reset(&pdev->dev, simpledrm_device_release_clocks, sdev); err: while (i) { --i; if (sdev->clks[i]) { clk_disable_unprepare(sdev->clks[i]); clk_put(sdev->clks[i]); } } return ret; } #else static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) { return 0; } #endif #if defined CONFIG_OF && defined CONFIG_REGULATOR #define SUPPLY_SUFFIX "-supply" /* * Regulator handling code. * * Here we handle the num-supplies and vin*-supply properties of our * "simple-framebuffer" dt node. This is necessary so that we can make sure * that any regulators needed by the display hardware that the bootloader * set up for us (and for which it provided a simplefb dt node), stay up, * for the life of the simplefb driver. * * When the driver unloads, we cleanly disable, and then release the * regulators. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the regulator definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_regulators(void *res) { struct simpledrm_device *sdev = simpledrm_device_of_dev(res); unsigned int i; for (i = 0; i < sdev->regulator_count; ++i) { if (sdev->regulators[i]) { regulator_disable(sdev->regulators[i]); regulator_put(sdev->regulators[i]); } } } static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) { struct drm_device *dev = &sdev->dev; struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct property *prop; struct regulator *regulator; const char *p; unsigned int count = 0, i = 0; int ret; if (dev_get_platdata(&pdev->dev) || !of_node) return 0; /* Count the number of regulator supplies */ for_each_property_of_node(of_node, prop) { p = strstr(prop->name, SUPPLY_SUFFIX); if (p && p != prop->name) ++count; } if (!count) return 0; sdev->regulators = drmm_kzalloc(dev, count * sizeof(sdev->regulators[0]), GFP_KERNEL); if (!sdev->regulators) return -ENOMEM; for_each_property_of_node(of_node, prop) { char name[32]; /* 32 is max size of property name */ size_t len; p = strstr(prop->name, SUPPLY_SUFFIX); if (!p || p == prop->name) continue; len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; strscpy(name, prop->name, min(sizeof(name), len)); regulator = regulator_get_optional(&pdev->dev, name); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); if (ret == -EPROBE_DEFER) goto err; drm_err(dev, "regulator %s not found: %d\n", name, ret); continue; } ret = regulator_enable(regulator); if (ret) { drm_err(dev, "failed to enable regulator %u: %d\n", i, ret); regulator_put(regulator); continue; } sdev->regulators[i++] = regulator; } sdev->regulator_count = i; return devm_add_action_or_reset(&pdev->dev, simpledrm_device_release_regulators, sdev); err: while (i) { --i; if (sdev->regulators[i]) { regulator_disable(sdev->regulators[i]); regulator_put(sdev->regulators[i]); } } return ret; } #else static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) { return 0; } #endif #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS /* * Generic power domain handling code. * * Here we handle the power-domains properties of our "simple-framebuffer" * dt node. This is only necessary if there is more than one power-domain. * A single power-domains is handled automatically by the driver core. Multiple * power-domains have to be handled by drivers since the driver core can't know * the correct power sequencing. Power sequencing is not an issue for simpledrm * since the bootloader has put the power domains already in the correct state. * simpledrm has only to ensure they remain active for its lifetime. * * When the driver unloads, we detach from the power-domains. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up the "simple-framebuffer" dt node, and the PM domain providers in the * device tree. Chances are that there are no adverse effects, and if there are, * a clean teardown of the fb probe will not help us much either. So just * complain and carry on, and hope that the user actually gets a working fb at * the end of things. */