^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * omap_device implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009-2010 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Paul Walmsley, Kevin Hilman
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Developed in collaboration with (alphabetical order): Benoit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Cousson, Thara Gopinath, Tony Lindgren, Rajendra Nayak, Vikram
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Woodruff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * This code provides a consistent interface for OMAP device drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * to control power management and interconnect properties of their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * In the medium- to long-term, this code should be implemented as a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * proper omap_bus/omap_device in Linux, no more platform_data func
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * pointers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/clkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include "soc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include "omap_device.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include "omap_hwmod.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Private functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static void _add_clkdev(struct omap_device *od, const char *clk_alias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const char *clk_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct clk *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (!clk_alias || !clk_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) dev_dbg(&od->pdev->dev, "Creating %s -> %s\n", clk_alias, clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (!IS_ERR(r)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) dev_dbg(&od->pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) "alias %s already exists\n", clk_alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) clk_put(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) r = clk_get_sys(NULL, clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (IS_ERR(r)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct of_phandle_args clkspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) clkspec.np = of_find_node_by_name(NULL, clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) r = of_clk_get_from_provider(&clkspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) rc = clk_register_clkdev(r, clk_alias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) dev_name(&od->pdev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) clk_name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (rc == -ENODEV || rc == -ENOMEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dev_err(&od->pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) "clkdev_alloc for %s failed\n", clk_alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) dev_err(&od->pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) "clk_get for %s failed\n", clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * and main clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * @od: struct omap_device *od
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * @oh: struct omap_hwmod *oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * For the main clock and every optional clock present per hwmod per
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * omap_device, this function adds an entry in the clkdev table of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * form <dev-id=dev_name, con-id=role> if it does not exist already.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * The function is called from inside omap_device_build_ss(), after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * omap_device_register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * This allows drivers to get a pointer to its optional clocks based on its role
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * by calling clk_get(<dev*>, <role>).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * In the case of the main clock, a "fck" alias is used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void _add_hwmod_clocks_clkdev(struct omap_device *od,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) _add_clkdev(od, "fck", oh->main_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) for (i = 0; i < oh->opt_clks_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * omap_device_build_from_dt - build an omap_device with multiple hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * @pdev: The platform device to update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * Function for building an omap_device already registered from device-tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * Returns 0 or PTR_ERR() on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int omap_device_build_from_dt(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct omap_hwmod **hwmods;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct device_node *node = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) const char *oh_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int oh_cnt, i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) bool device_active = false, skip_pm_domain = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) oh_cnt = of_property_count_strings(node, "ti,hwmods");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (oh_cnt <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* SDMA still needs special handling for omap_device_build() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ret = of_property_read_string_index(node, "ti,hwmods", 0, &oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (!ret && (!strncmp("dma_system", oh_name, 10) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) !strncmp("dma", oh_name, 3)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) skip_pm_domain = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Use ti-sysc driver instead of omap_device? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (!skip_pm_domain &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) !omap_hwmod_parse_module_range(NULL, node, &res))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) hwmods = kcalloc(oh_cnt, sizeof(struct omap_hwmod *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (!hwmods) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) goto odbfd_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) for (i = 0; i < oh_cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) oh = omap_hwmod_lookup(oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!oh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) goto odbfd_exit1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) hwmods[i] = oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (oh->flags & HWMOD_INIT_NO_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) device_active = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) od = omap_device_alloc(pdev, hwmods, oh_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (IS_ERR(od)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ret = PTR_ERR(od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) goto odbfd_exit1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* Fix up missing resource names */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) for (i = 0; i < pdev->num_resources; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct resource *r = &pdev->resource[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (r->name == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) r->name = dev_name(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (!skip_pm_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (device_active) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) omap_device_enable(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) pm_runtime_set_active(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) odbfd_exit1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) kfree(hwmods);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) odbfd_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* if data/we are at fault.. load up a fail handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) dev_pm_domain_set(&pdev->dev, &omap_device_fail_pm_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static int _omap_device_notifier_call(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned long event, void *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case BUS_NOTIFY_REMOVED_DEVICE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (pdev->archdata.od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) omap_device_delete(pdev->archdata.od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) case BUS_NOTIFY_UNBOUND_DRIVER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) dev_info(dev, "enabled after unload, idling\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) err = omap_device_idle(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) dev_err(dev, "failed to idle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) case BUS_NOTIFY_BIND_DRIVER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (od) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (od->_state == OMAP_DEVICE_STATE_ENABLED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) pm_runtime_status_suspended(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pm_runtime_set_active(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case BUS_NOTIFY_ADD_DEVICE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (pdev->dev.of_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) omap_device_build_from_dt(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) omap_auxdata_legacy_init(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) od->_driver_status = event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * @od: struct omap_device *od
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Enable all underlying hwmods. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static int _omap_device_enable_hwmods(struct omap_device *od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) for (i = 0; i < od->hwmods_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) ret |= omap_hwmod_enable(od->hwmods[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * @od: struct omap_device *od
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * Idle all underlying hwmods. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) static int _omap_device_idle_hwmods(struct omap_device *od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) for (i = 0; i < od->hwmods_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ret |= omap_hwmod_idle(od->hwmods[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Public functions for use by core code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * omap_device_get_context_loss_count - get lost context count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * @pdev: The platform device to update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * Using the primary hwmod, query the context loss count for this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * Callers should consider context for this device lost any time this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * function returns a value different than the value the caller got
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * the last time it called this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * If any hwmods exist for the omap_device associated with @pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * return the context loss counter for that hwmod, otherwise return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) int omap_device_get_context_loss_count(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) u32 ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (od->hwmods_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * omap_device_alloc - allocate an omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * @pdev: platform_device that will be included in this omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * @ohs: ptr to the omap_hwmod for this omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * @oh_cnt: the size of the ohs list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) * Convenience function for allocating an omap_device structure and filling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * hwmods, and resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * Returns an struct omap_device pointer or ERR_PTR() on error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct omap_device *omap_device_alloc(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct omap_hwmod **ohs, int oh_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) int ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct omap_hwmod **hwmods;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (!od) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) goto oda_exit1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) od->hwmods_cnt = oh_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (!hwmods)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) goto oda_exit2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) od->hwmods = hwmods;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) od->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) pdev->archdata.od = od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) for (i = 0; i < oh_cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) hwmods[i]->od = od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) _add_hwmod_clocks_clkdev(od, hwmods[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) oda_exit2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) kfree(od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) oda_exit1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) void omap_device_delete(struct omap_device *od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) od->pdev->archdata.od = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) kfree(od->hwmods);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) kfree(od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int _od_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ret = pm_generic_runtime_suspend(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return omap_device_idle(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int _od_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) ret = omap_device_enable(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) dev_err(dev, "use pm_runtime_put_sync_suspend() in driver?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return pm_generic_runtime_resume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static int _od_fail_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static int _od_fail_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) #ifdef CONFIG_SUSPEND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static int _od_suspend_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) struct omap_device *od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* Don't attempt late suspend on a driver that is not bound */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ret = pm_generic_suspend_noirq(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (!ret && !pm_runtime_status_suspended(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (pm_generic_runtime_suspend(dev) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) omap_device_idle(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) od->flags |= OMAP_DEVICE_SUSPENDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static int _od_resume_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct omap_device *od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (od->flags & OMAP_DEVICE_SUSPENDED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) od->flags &= ~OMAP_DEVICE_SUSPENDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) omap_device_enable(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) pm_generic_runtime_resume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return pm_generic_resume_noirq(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) #define _od_suspend_noirq NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) #define _od_resume_noirq NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) struct dev_pm_domain omap_device_fail_pm_domain = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) SET_RUNTIME_PM_OPS(_od_fail_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) _od_fail_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) struct dev_pm_domain omap_device_pm_domain = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) USE_PLATFORM_PM_SLEEP_OPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) _od_resume_noirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * omap_device_register - register an omap_device with one omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * @pdev: the platform device (omap_device) to register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * Register the omap_device structure. This currently just calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) * platform_device_register() on the underlying platform_device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) * Returns the return value of platform_device_register().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) int omap_device_register(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) pr_debug("omap_device: %s: registering\n", pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return platform_device_add(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /* Public functions for use by device drivers through struct platform_data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * omap_device_enable - fully activate an omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * @pdev: the platform device to activate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * Do whatever is necessary for the hwmods underlying omap_device @od
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * to be accessible and ready to operate. This generally involves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * enabling clocks, setting SYSCONFIG registers; and in the future may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * involve remuxing pins. Device drivers should call this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * indirectly via pm_runtime_get*(). Returns -EINVAL if called when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * the omap_device is already enabled, or passes along the return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * value of _omap_device_enable_hwmods().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int omap_device_enable(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) dev_warn(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) "omap_device: %s() called from invalid state %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) __func__, od->_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) ret = _omap_device_enable_hwmods(od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) od->_state = OMAP_DEVICE_STATE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * omap_device_idle - idle an omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * @pdev: The platform_device (omap_device) to idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * Idle omap_device @od. Device drivers call this function indirectly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * currently enabled, or passes along the return value of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * _omap_device_idle_hwmods().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) int omap_device_idle(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct omap_device *od;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) dev_warn(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) "omap_device: %s() called from invalid state %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) __func__, od->_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) ret = _omap_device_idle_hwmods(od);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) od->_state = OMAP_DEVICE_STATE_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * omap_device_assert_hardreset - set a device's hardreset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * @pdev: struct platform_device * to reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * @name: const char * name of the reset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * Set the hardreset line identified by @name on the IP blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * associated with the hwmods backing the platform_device @pdev. All
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * of the hwmods associated with @pdev must have the same hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * line linked to them for this to work. Passes along the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * of omap_hwmod_assert_hardreset() in the event of any failure, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) int omap_device_assert_hardreset(struct platform_device *pdev, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) struct omap_device *od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) for (i = 0; i < od->hwmods_cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) ret = omap_hwmod_assert_hardreset(od->hwmods[i], name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) * omap_device_deassert_hardreset - release a device's hardreset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) * @pdev: struct platform_device * to reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) * @name: const char * name of the reset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) * Release the hardreset line identified by @name on the IP blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * associated with the hwmods backing the platform_device @pdev. All
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) * of the hwmods associated with @pdev must have the same hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) * line linked to them for this to work. Passes along the return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * value of omap_hwmod_deassert_hardreset() in the event of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * failure, or returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) int omap_device_deassert_hardreset(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct omap_device *od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) for (i = 0; i < od->hwmods_cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * omap_device_get_by_hwmod_name() - convert a hwmod name to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * device pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * @oh_name: name of the hwmod device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * Returns back a struct device * pointer associated with a hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * device represented by a hwmod_name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) struct device *omap_device_get_by_hwmod_name(const char *oh_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (!oh_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) WARN(1, "%s: no hwmod name!\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) oh = omap_hwmod_lookup(oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (!oh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) WARN(1, "%s: no hwmod for %s\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (!oh->od) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) WARN(1, "%s: no omap_device for %s\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return &oh->od->pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static struct notifier_block platform_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) .notifier_call = _omap_device_notifier_call,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static int __init omap_device_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) bus_register_notifier(&platform_bus_type, &platform_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) omap_postcore_initcall(omap_device_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * omap_device_late_idle - idle devices without drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * @dev: struct device * associated with omap_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * @data: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * Check the driver bound status of this device, and idle it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) * if there is no driver attached.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static int __init omap_device_late_idle(struct device *dev, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) struct platform_device *pdev = to_platform_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) struct omap_device *od = to_omap_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (!od)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * If omap_device state is enabled, but has no driver bound,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * idle it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * Some devices (like memory controllers) are always kept
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * enabled, and should not be idled even with no drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) for (i = 0; i < od->hwmods_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) od->_driver_status != BUS_NOTIFY_BIND_DRIVER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) dev_warn(dev, "%s: enabled but no driver. Idling\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) omap_device_idle(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) static int __init omap_device_late_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) omap_late_initcall_sync(omap_device_late_init);