blob: 6ee3ad3dd95a94dc9cdec6db6d3a35253ecf2e69 [file] [log] [blame]
Paul Walmsleyb04b65a2009-09-03 20:14:05 +03001/*
2 * omap_device implementation
3 *
Paul Walmsley887adea2010-07-26 16:34:33 -06004 * Copyright (C) 2009-2010 Nokia Corporation
Paul Walmsley4788da22010-05-18 20:24:05 -06005 * Paul Walmsley, Kevin Hilman
Paul Walmsleyb04b65a2009-09-03 20:14:05 +03006 *
7 * Developed in collaboration with (alphabetical order): Benoit
Paul Walmsley4788da22010-05-18 20:24:05 -06008 * Cousson, Thara Gopinath, Tony Lindgren, Rajendra Nayak, Vikram
Paul Walmsleyb04b65a2009-09-03 20:14:05 +03009 * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
10 * Woodruff
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This code provides a consistent interface for OMAP device drivers
17 * to control power management and interconnect properties of their
18 * devices.
19 *
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -070020 * In the medium- to long-term, this code should be implemented as a
21 * proper omap_bus/omap_device in Linux, no more platform_data func
22 * pointers
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030023 *
24 *
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030025 */
26#undef DEBUG
27
28#include <linux/kernel.h>
29#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030031#include <linux/err.h>
32#include <linux/io.h>
Partha Basak4ef7aca2010-09-21 19:23:04 +020033#include <linux/clk.h>
Rajendra Nayakda0653f2011-02-25 15:40:21 -070034#include <linux/clkdev.h>
Kevin Hilman345f79b2011-05-31 16:08:09 -070035#include <linux/pm_runtime.h>
Benoit Coussondc2d07e2011-08-10 13:32:08 +020036#include <linux/of.h>
37#include <linux/notifier.h>
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030038
Tony Lindgren25c7d492012-10-02 17:25:48 -070039#include "omap_device.h"
Tony Lindgren2a296c82012-10-02 17:41:35 -070040#include "omap_hwmod.h"
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030041
Paul Walmsleyb04b65a2009-09-03 20:14:05 +030042/* Private functions */
43
Benoit Coussonbf1e0772011-07-10 05:54:12 -060044static void _add_clkdev(struct omap_device *od, const char *clk_alias,
45 const char *clk_name)
46{
47 struct clk *r;
48 struct clk_lookup *l;
49
50 if (!clk_alias || !clk_name)
51 return;
52
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070053 dev_dbg(&od->pdev->dev, "Creating %s -> %s\n", clk_alias, clk_name);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060054
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070055 r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060056 if (!IS_ERR(r)) {
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070057 dev_warn(&od->pdev->dev,
Kevin Hilman49882c92011-07-21 09:58:36 -070058 "alias %s already exists\n", clk_alias);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060059 clk_put(r);
60 return;
61 }
62
Rajendra Nayak6ea74cb2012-09-22 02:24:16 -060063 r = clk_get(NULL, clk_name);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060064 if (IS_ERR(r)) {
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070065 dev_err(&od->pdev->dev,
Rajendra Nayak6ea74cb2012-09-22 02:24:16 -060066 "clk_get for %s failed\n", clk_name);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060067 return;
68 }
69
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070070 l = clkdev_alloc(r, clk_alias, dev_name(&od->pdev->dev));
Benoit Coussonbf1e0772011-07-10 05:54:12 -060071 if (!l) {
Kevin Hilmand66b3fe2011-07-21 13:58:51 -070072 dev_err(&od->pdev->dev,
Kevin Hilman49882c92011-07-21 09:58:36 -070073 "clkdev_alloc for %s failed\n", clk_alias);
Benoit Coussonbf1e0772011-07-10 05:54:12 -060074 return;
75 }
76
77 clkdev_add(l);
78}
79
Partha Basak4ef7aca2010-09-21 19:23:04 +020080/**
Benoit Coussonbf1e0772011-07-10 05:54:12 -060081 * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
82 * and main clock
Partha Basak4ef7aca2010-09-21 19:23:04 +020083 * @od: struct omap_device *od
Benoit Coussonbf1e0772011-07-10 05:54:12 -060084 * @oh: struct omap_hwmod *oh
Partha Basak4ef7aca2010-09-21 19:23:04 +020085 *
Benoit Coussonbf1e0772011-07-10 05:54:12 -060086 * For the main clock and every optional clock present per hwmod per
87 * omap_device, this function adds an entry in the clkdev table of the
88 * form <dev-id=dev_name, con-id=role> if it does not exist already.
Partha Basak4ef7aca2010-09-21 19:23:04 +020089 *
90 * The function is called from inside omap_device_build_ss(), after
91 * omap_device_register.
92 *
93 * This allows drivers to get a pointer to its optional clocks based on its role
94 * by calling clk_get(<dev*>, <role>).
Benoit Coussonbf1e0772011-07-10 05:54:12 -060095 * In the case of the main clock, a "fck" alias is used.
Partha Basak4ef7aca2010-09-21 19:23:04 +020096 *
97 * No return value.
98 */
Benoit Coussonbf1e0772011-07-10 05:54:12 -060099static void _add_hwmod_clocks_clkdev(struct omap_device *od,
100 struct omap_hwmod *oh)
Partha Basak4ef7aca2010-09-21 19:23:04 +0200101{
102 int i;
103
Benoit Coussonbf1e0772011-07-10 05:54:12 -0600104 _add_clkdev(od, "fck", oh->main_clk);
Partha Basak4ef7aca2010-09-21 19:23:04 +0200105
Benoit Coussonbf1e0772011-07-10 05:54:12 -0600106 for (i = 0; i < oh->opt_clks_cnt; i++)
107 _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
Partha Basak4ef7aca2010-09-21 19:23:04 +0200108}
109
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300110
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200111/**
112 * omap_device_build_from_dt - build an omap_device with multiple hwmods
113 * @pdev_name: name of the platform_device driver to use
114 * @pdev_id: this platform_device's connection ID
115 * @oh: ptr to the single omap_hwmod that backs this omap_device
116 * @pdata: platform_data ptr to associate with the platform_device
117 * @pdata_len: amount of memory pointed to by @pdata
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200118 *
119 * Function for building an omap_device already registered from device-tree
120 *
121 * Returns 0 or PTR_ERR() on error.
122 */
123static int omap_device_build_from_dt(struct platform_device *pdev)
124{
125 struct omap_hwmod **hwmods;
126 struct omap_device *od;
127 struct omap_hwmod *oh;
128 struct device_node *node = pdev->dev.of_node;
129 const char *oh_name;
130 int oh_cnt, i, ret = 0;
131
132 oh_cnt = of_property_count_strings(node, "ti,hwmods");
133 if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
Benoit Cousson5dc06b72012-01-20 18:14:00 +0100134 dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200135 return -ENODEV;
136 }
137
138 hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
139 if (!hwmods) {
140 ret = -ENOMEM;
141 goto odbfd_exit;
142 }
143
144 for (i = 0; i < oh_cnt; i++) {
145 of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
146 oh = omap_hwmod_lookup(oh_name);
147 if (!oh) {
148 dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
149 oh_name);
150 ret = -EINVAL;
151 goto odbfd_exit1;
152 }
153 hwmods[i] = oh;
154 }
155
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700156 od = omap_device_alloc(pdev, hwmods, oh_cnt);
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200157 if (!od) {
158 dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
159 oh_name);
160 ret = PTR_ERR(od);
161 goto odbfd_exit1;
162 }
163
Peter Ujfalusi3956a1a2012-08-23 16:54:09 +0300164 /* Fix up missing resource names */
165 for (i = 0; i < pdev->num_resources; i++) {
166 struct resource *r = &pdev->resource[i];
167
168 if (r->name == NULL)
169 r->name = dev_name(&pdev->dev);
170 }
171
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200172 if (of_get_property(node, "ti,no_idle_on_suspend", NULL))
173 omap_device_disable_idle_on_suspend(pdev);
174
175 pdev->dev.pm_domain = &omap_device_pm_domain;
176
177odbfd_exit1:
178 kfree(hwmods);
179odbfd_exit:
180 return ret;
181}
182
183static int _omap_device_notifier_call(struct notifier_block *nb,
184 unsigned long event, void *dev)
185{
186 struct platform_device *pdev = to_platform_device(dev);
Kevin Hilmane7533452012-07-10 11:13:16 -0700187 struct omap_device *od;
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200188
189 switch (event) {
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200190 case BUS_NOTIFY_DEL_DEVICE:
191 if (pdev->archdata.od)
192 omap_device_delete(pdev->archdata.od);
193 break;
Kevin Hilmane7533452012-07-10 11:13:16 -0700194 case BUS_NOTIFY_ADD_DEVICE:
195 if (pdev->dev.of_node)
196 omap_device_build_from_dt(pdev);
197 /* fall through */
198 default:
199 od = to_omap_device(pdev);
200 if (od)
201 od->_driver_status = event;
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200202 }
203
204 return NOTIFY_DONE;
205}
206
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700207/**
208 * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
209 * @od: struct omap_device *od
210 *
211 * Enable all underlying hwmods. Returns 0.
212 */
213static int _omap_device_enable_hwmods(struct omap_device *od)
214{
215 int i;
216
217 for (i = 0; i < od->hwmods_cnt; i++)
218 omap_hwmod_enable(od->hwmods[i]);
219
220 /* XXX pass along return value here? */
221 return 0;
222}
223
224/**
225 * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
226 * @od: struct omap_device *od
227 *
228 * Idle all underlying hwmods. Returns 0.
229 */
230static int _omap_device_idle_hwmods(struct omap_device *od)
231{
232 int i;
233
234 for (i = 0; i < od->hwmods_cnt; i++)
235 omap_hwmod_idle(od->hwmods[i]);
236
237 /* XXX pass along return value here? */
238 return 0;
239}
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200240
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300241/* Public functions for use by core code */
242
243/**
Kevin Hilmanc80705a2010-12-21 21:31:55 -0700244 * omap_device_get_context_loss_count - get lost context count
245 * @od: struct omap_device *
246 *
247 * Using the primary hwmod, query the context loss count for this
248 * device.
249 *
250 * Callers should consider context for this device lost any time this
251 * function returns a value different than the value the caller got
252 * the last time it called this function.
253 *
254 * If any hwmods exist for the omap_device assoiated with @pdev,
255 * return the context loss counter for that hwmod, otherwise return
256 * zero.
257 */
Tomi Valkeinenfc013872011-06-09 16:56:23 +0300258int omap_device_get_context_loss_count(struct platform_device *pdev)
Kevin Hilmanc80705a2010-12-21 21:31:55 -0700259{
260 struct omap_device *od;
261 u32 ret = 0;
262
Kevin Hilman8f0d69d2011-07-09 19:15:20 -0600263 od = to_omap_device(pdev);
Kevin Hilmanc80705a2010-12-21 21:31:55 -0700264
265 if (od->hwmods_cnt)
266 ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
267
268 return ret;
269}
270
271/**
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300272 * omap_device_count_resources - count number of struct resource entries needed
273 * @od: struct omap_device *
Peter Ujfalusidad41912012-11-21 16:15:17 -0700274 * @flags: Type of resources to include when counting (IRQ/DMA/MEM)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300275 *
276 * Count the number of struct resource entries needed for this
277 * omap_device @od. Used by omap_device_build_ss() to determine how
278 * much memory to allocate before calling
279 * omap_device_fill_resources(). Returns the count.
280 */
Peter Ujfalusidad41912012-11-21 16:15:17 -0700281static int omap_device_count_resources(struct omap_device *od,
282 unsigned long flags)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300283{
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300284 int c = 0;
285 int i;
286
Kishon Vijay Abraham If39f4892010-09-24 10:23:18 -0600287 for (i = 0; i < od->hwmods_cnt; i++)
Peter Ujfalusidad41912012-11-21 16:15:17 -0700288 c += omap_hwmod_count_resources(od->hwmods[i], flags);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300289
Paul Walmsley7852ec02012-07-26 00:54:26 -0600290 pr_debug("omap_device: %s: counted %d total resources across %d hwmods\n",
291 od->pdev->name, c, od->hwmods_cnt);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300292
293 return c;
294}
295
296/**
297 * omap_device_fill_resources - fill in array of struct resource
298 * @od: struct omap_device *
299 * @res: pointer to an array of struct resource to be filled in
300 *
301 * Populate one or more empty struct resource pointed to by @res with
302 * the resource data for this omap_device @od. Used by
303 * omap_device_build_ss() after calling omap_device_count_resources().
304 * Ideally this function would not be needed at all. If omap_device
305 * replaces platform_device, then we can specify our own
306 * get_resource()/ get_irq()/etc functions that use the underlying
307 * omap_hwmod information. Or if platform_device is extended to use
308 * subarchitecture-specific function pointers, the various
309 * platform_device functions can simply call omap_device internal
310 * functions to get device resources. Hacking around the existing
311 * platform_device code wastes memory. Returns 0.
312 */
Kevin Hilmana2a28ad2011-07-21 14:14:35 -0700313static int omap_device_fill_resources(struct omap_device *od,
314 struct resource *res)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300315{
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300316 int i, r;
317
Kishon Vijay Abraham If39f4892010-09-24 10:23:18 -0600318 for (i = 0; i < od->hwmods_cnt; i++) {
319 r = omap_hwmod_fill_resources(od->hwmods[i], res);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300320 res += r;
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300321 }
322
323 return 0;
324}
325
326/**
Vaibhav Hiremathb82b04e2012-08-29 15:18:11 +0530327 * _od_fill_dma_resources - fill in array of struct resource with dma resources
328 * @od: struct omap_device *
329 * @res: pointer to an array of struct resource to be filled in
330 *
331 * Populate one or more empty struct resource pointed to by @res with
332 * the dma resource data for this omap_device @od. Used by
333 * omap_device_alloc() after calling omap_device_count_resources().
334 *
335 * Ideally this function would not be needed at all. If we have
336 * mechanism to get dma resources from DT.
337 *
338 * Returns 0.
339 */
340static int _od_fill_dma_resources(struct omap_device *od,
341 struct resource *res)
342{
343 int i, r;
344
345 for (i = 0; i < od->hwmods_cnt; i++) {
346 r = omap_hwmod_fill_dma_resources(od->hwmods[i], res);
347 res += r;
348 }
349
350 return 0;
351}
352
353/**
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200354 * omap_device_alloc - allocate an omap_device
355 * @pdev: platform_device that will be included in this omap_device
356 * @oh: ptr to the single omap_hwmod that backs this omap_device
357 * @pdata: platform_data ptr to associate with the platform_device
358 * @pdata_len: amount of memory pointed to by @pdata
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200359 *
360 * Convenience function for allocating an omap_device structure and filling
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700361 * hwmods, and resources.
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200362 *
363 * Returns an struct omap_device pointer or ERR_PTR() on error;
364 */
Ohad Ben-Cohen993e4fb2012-02-20 09:43:29 -0800365struct omap_device *omap_device_alloc(struct platform_device *pdev,
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700366 struct omap_hwmod **ohs, int oh_cnt)
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200367{
368 int ret = -ENOMEM;
369 struct omap_device *od;
370 struct resource *res = NULL;
371 int i, res_count;
372 struct omap_hwmod **hwmods;
373
374 od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
375 if (!od) {
376 ret = -ENOMEM;
377 goto oda_exit1;
378 }
379 od->hwmods_cnt = oh_cnt;
380
381 hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
382 if (!hwmods)
383 goto oda_exit2;
384
385 od->hwmods = hwmods;
386 od->pdev = pdev;
387
Vaibhav Hiremathb82b04e2012-08-29 15:18:11 +0530388 /*
Peter Ujfalusic567b052012-11-21 16:15:18 -0700389 * Non-DT Boot:
390 * Here, pdev->num_resources = 0, and we should get all the
391 * resources from hwmod.
392 *
Vaibhav Hiremathb82b04e2012-08-29 15:18:11 +0530393 * DT Boot:
394 * OF framework will construct the resource structure (currently
395 * does for MEM & IRQ resource) and we should respect/use these
396 * resources, killing hwmod dependency.
397 * If pdev->num_resources > 0, we assume that MEM & IRQ resources
398 * have been allocated by OF layer already (through DTB).
Peter Ujfalusic567b052012-11-21 16:15:18 -0700399 * As preparation for the future we examine the OF provided resources
400 * to see if we have DMA resources provided already. In this case
401 * there is no need to update the resources for the device, we use the
402 * OF provided ones.
Vaibhav Hiremathb82b04e2012-08-29 15:18:11 +0530403 *
404 * TODO: Once DMA resource is available from OF layer, we should
405 * kill filling any resources from hwmod.
406 */
Peter Ujfalusic567b052012-11-21 16:15:18 -0700407 if (!pdev->num_resources) {
408 /* Count all resources for the device */
409 res_count = omap_device_count_resources(od, IORESOURCE_IRQ |
410 IORESOURCE_DMA |
411 IORESOURCE_MEM);
412 } else {
413 /* Take a look if we already have DMA resource via DT */
414 for (i = 0; i < pdev->num_resources; i++) {
415 struct resource *r = &pdev->resource[i];
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200416
Peter Ujfalusic567b052012-11-21 16:15:18 -0700417 /* We have it, no need to touch the resources */
418 if (r->flags == IORESOURCE_DMA)
419 goto have_everything;
Vaibhav Hiremathb82b04e2012-08-29 15:18:11 +0530420 }
Peter Ujfalusic567b052012-11-21 16:15:18 -0700421 /* Count only DMA resources for the device */
422 res_count = omap_device_count_resources(od, IORESOURCE_DMA);
423 /* The device has no DMA resource, no need for update */
424 if (!res_count)
425 goto have_everything;
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200426
Peter Ujfalusic567b052012-11-21 16:15:18 -0700427 res_count += pdev->num_resources;
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200428 }
429
Peter Ujfalusic567b052012-11-21 16:15:18 -0700430 /* Allocate resources memory to account for new resources */
431 res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
432 if (!res)
433 goto oda_exit3;
434
435 if (!pdev->num_resources) {
436 dev_dbg(&pdev->dev, "%s: using %d resources from hwmod\n",
437 __func__, res_count);
438 omap_device_fill_resources(od, res);
439 } else {
440 dev_dbg(&pdev->dev,
441 "%s: appending %d DMA resources from hwmod\n",
442 __func__, res_count - pdev->num_resources);
443 memcpy(res, pdev->resource,
444 sizeof(struct resource) * pdev->num_resources);
445 _od_fill_dma_resources(od, &res[pdev->num_resources]);
446 }
447
448 ret = platform_device_add_resources(pdev, res, res_count);
449 kfree(res);
450
451 if (ret)
452 goto oda_exit3;
453
454have_everything:
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200455 pdev->archdata.od = od;
456
457 for (i = 0; i < oh_cnt; i++) {
458 hwmods[i]->od = od;
459 _add_hwmod_clocks_clkdev(od, hwmods[i]);
460 }
461
462 return od;
463
464oda_exit3:
465 kfree(hwmods);
466oda_exit2:
467 kfree(od);
468oda_exit1:
469 dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret);
470
471 return ERR_PTR(ret);
472}
473
Ohad Ben-Cohen993e4fb2012-02-20 09:43:29 -0800474void omap_device_delete(struct omap_device *od)
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200475{
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200476 if (!od)
477 return;
478
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200479 od->pdev->archdata.od = NULL;
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200480 kfree(od->hwmods);
481 kfree(od);
482}
483
484/**
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300485 * omap_device_build - build and register an omap_device with one omap_hwmod
486 * @pdev_name: name of the platform_device driver to use
487 * @pdev_id: this platform_device's connection ID
488 * @oh: ptr to the single omap_hwmod that backs this omap_device
489 * @pdata: platform_data ptr to associate with the platform_device
490 * @pdata_len: amount of memory pointed to by @pdata
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300491 *
492 * Convenience function for building and registering a single
493 * omap_device record, which in turn builds and registers a
494 * platform_device record. See omap_device_build_ss() for more
495 * information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
496 * passes along the return value of omap_device_build_ss().
497 */
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700498struct platform_device __init *omap_device_build(const char *pdev_name,
499 int pdev_id,
500 struct omap_hwmod *oh,
501 void *pdata, int pdata_len)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300502{
503 struct omap_hwmod *ohs[] = { oh };
504
505 if (!oh)
506 return ERR_PTR(-EINVAL);
507
508 return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700509 pdata_len);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300510}
511
512/**
513 * omap_device_build_ss - build and register an omap_device with multiple hwmods
514 * @pdev_name: name of the platform_device driver to use
515 * @pdev_id: this platform_device's connection ID
516 * @oh: ptr to the single omap_hwmod that backs this omap_device
517 * @pdata: platform_data ptr to associate with the platform_device
518 * @pdata_len: amount of memory pointed to by @pdata
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300519 *
520 * Convenience function for building and registering an omap_device
521 * subsystem record. Subsystem records consist of multiple
522 * omap_hwmods. This function in turn builds and registers a
523 * platform_device record. Returns an ERR_PTR() on error, or passes
524 * along the return value of omap_device_register().
525 */
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700526struct platform_device __init *omap_device_build_ss(const char *pdev_name,
527 int pdev_id,
528 struct omap_hwmod **ohs,
529 int oh_cnt, void *pdata,
530 int pdata_len)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300531{
532 int ret = -ENOMEM;
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700533 struct platform_device *pdev;
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300534 struct omap_device *od;
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300535
536 if (!ohs || oh_cnt == 0 || !pdev_name)
537 return ERR_PTR(-EINVAL);
538
539 if (!pdata && pdata_len > 0)
540 return ERR_PTR(-EINVAL);
541
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700542 pdev = platform_device_alloc(pdev_name, pdev_id);
543 if (!pdev) {
544 ret = -ENOMEM;
545 goto odbs_exit;
546 }
547
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200548 /* Set the dev_name early to allow dev_xxx in omap_device_alloc */
549 if (pdev->id != -1)
550 dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
551 else
552 dev_set_name(&pdev->dev, "%s", pdev->name);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300553
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700554 od = omap_device_alloc(pdev, ohs, oh_cnt);
Wei Yongjuna87e6622012-09-21 14:32:04 +0800555 if (IS_ERR(od))
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700556 goto odbs_exit1;
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300557
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700558 ret = platform_device_add_data(pdev, pdata, pdata_len);
Artem Bityutskiy49b368a2010-07-12 13:38:07 +0000559 if (ret)
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200560 goto odbs_exit2;
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700561
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700562 ret = omap_device_register(pdev);
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700563 if (ret)
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200564 goto odbs_exit2;
Kevin Hilman06563582010-07-26 16:34:30 -0600565
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700566 return pdev;
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300567
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700568odbs_exit2:
Benoit Coussona4f6cdb2011-08-09 16:47:01 +0200569 omap_device_delete(od);
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700570odbs_exit1:
571 platform_device_put(pdev);
572odbs_exit:
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300573
574 pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
575
576 return ERR_PTR(ret);
577}
578
Kevin Hilman256a5432011-07-12 22:48:03 +0200579#ifdef CONFIG_PM_RUNTIME
Kevin Hilman638080c2011-04-29 00:36:42 +0200580static int _od_runtime_suspend(struct device *dev)
581{
582 struct platform_device *pdev = to_platform_device(dev);
Kevin Hilman345f79b2011-05-31 16:08:09 -0700583 int ret;
Kevin Hilman638080c2011-04-29 00:36:42 +0200584
Kevin Hilman345f79b2011-05-31 16:08:09 -0700585 ret = pm_generic_runtime_suspend(dev);
586
587 if (!ret)
588 omap_device_idle(pdev);
589
590 return ret;
591}
592
593static int _od_runtime_idle(struct device *dev)
594{
595 return pm_generic_runtime_idle(dev);
Kevin Hilman638080c2011-04-29 00:36:42 +0200596}
597
598static int _od_runtime_resume(struct device *dev)
599{
600 struct platform_device *pdev = to_platform_device(dev);
601
Kevin Hilman345f79b2011-05-31 16:08:09 -0700602 omap_device_enable(pdev);
603
604 return pm_generic_runtime_resume(dev);
Kevin Hilman638080c2011-04-29 00:36:42 +0200605}
Kevin Hilman256a5432011-07-12 22:48:03 +0200606#endif
Kevin Hilman638080c2011-04-29 00:36:42 +0200607
Kevin Hilmanc03f0072011-07-12 22:48:19 +0200608#ifdef CONFIG_SUSPEND
609static int _od_suspend_noirq(struct device *dev)
610{
611 struct platform_device *pdev = to_platform_device(dev);
612 struct omap_device *od = to_omap_device(pdev);
613 int ret;
614
Kevin Hilman72bb6f92012-07-10 15:29:04 -0700615 /* Don't attempt late suspend on a driver that is not bound */
616 if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
617 return 0;
618
Kevin Hilmanc03f0072011-07-12 22:48:19 +0200619 ret = pm_generic_suspend_noirq(dev);
620
621 if (!ret && !pm_runtime_status_suspended(dev)) {
622 if (pm_generic_runtime_suspend(dev) == 0) {
Paul Walmsleyb7c39a32012-03-03 13:15:33 -0700623 if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
624 omap_device_idle(pdev);
Kevin Hilmanc03f0072011-07-12 22:48:19 +0200625 od->flags |= OMAP_DEVICE_SUSPENDED;
626 }
627 }
628
629 return ret;
630}
631
632static int _od_resume_noirq(struct device *dev)
633{
634 struct platform_device *pdev = to_platform_device(dev);
635 struct omap_device *od = to_omap_device(pdev);
636
637 if ((od->flags & OMAP_DEVICE_SUSPENDED) &&
638 !pm_runtime_status_suspended(dev)) {
639 od->flags &= ~OMAP_DEVICE_SUSPENDED;
Paul Walmsleyb7c39a32012-03-03 13:15:33 -0700640 if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
641 omap_device_enable(pdev);
Kevin Hilmanc03f0072011-07-12 22:48:19 +0200642 pm_generic_runtime_resume(dev);
643 }
644
645 return pm_generic_resume_noirq(dev);
646}
Kevin Hilman126caf12011-09-01 10:59:36 -0700647#else
648#define _od_suspend_noirq NULL
649#define _od_resume_noirq NULL
Kevin Hilmanc03f0072011-07-12 22:48:19 +0200650#endif
651
Kevin Hilman3ec2dec2012-02-15 11:47:45 -0800652struct dev_pm_domain omap_device_pm_domain = {
Kevin Hilman638080c2011-04-29 00:36:42 +0200653 .ops = {
Kevin Hilman256a5432011-07-12 22:48:03 +0200654 SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
655 _od_runtime_idle)
Kevin Hilman638080c2011-04-29 00:36:42 +0200656 USE_PLATFORM_PM_SLEEP_OPS
Kevin Hilmanff353362011-08-25 15:31:14 +0200657 .suspend_noirq = _od_suspend_noirq,
658 .resume_noirq = _od_resume_noirq,
Kevin Hilman638080c2011-04-29 00:36:42 +0200659 }
660};
661
Thara Gopinathc23a97d2010-02-24 12:05:58 -0700662/**
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300663 * omap_device_register - register an omap_device with one omap_hwmod
664 * @od: struct omap_device * to register
665 *
666 * Register the omap_device structure. This currently just calls
667 * platform_device_register() on the underlying platform_device.
668 * Returns the return value of platform_device_register().
669 */
Ohad Ben-Cohen993e4fb2012-02-20 09:43:29 -0800670int omap_device_register(struct platform_device *pdev)
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300671{
Kevin Hilmanbfae4f82011-07-21 14:47:53 -0700672 pr_debug("omap_device: %s: registering\n", pdev->name);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300673
Kevin Hilmanbfae4f82011-07-21 14:47:53 -0700674 pdev->dev.pm_domain = &omap_device_pm_domain;
Kevin Hilmand66b3fe2011-07-21 13:58:51 -0700675 return platform_device_add(pdev);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300676}
677
678
679/* Public functions for use by device drivers through struct platform_data */
680
681/**
682 * omap_device_enable - fully activate an omap_device
683 * @od: struct omap_device * to activate
684 *
685 * Do whatever is necessary for the hwmods underlying omap_device @od
686 * to be accessible and ready to operate. This generally involves
687 * enabling clocks, setting SYSCONFIG registers; and in the future may
688 * involve remuxing pins. Device drivers should call this function
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700689 * indirectly via pm_runtime_get*(). Returns -EINVAL if called when
690 * the omap_device is already enabled, or passes along the return
691 * value of _omap_device_enable_hwmods().
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300692 */
693int omap_device_enable(struct platform_device *pdev)
694{
695 int ret;
696 struct omap_device *od;
697
Kevin Hilman8f0d69d2011-07-09 19:15:20 -0600698 od = to_omap_device(pdev);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300699
700 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
Kevin Hilman49882c92011-07-21 09:58:36 -0700701 dev_warn(&pdev->dev,
702 "omap_device: %s() called from invalid state %d\n",
703 __func__, od->_state);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300704 return -EINVAL;
705 }
706
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700707 ret = _omap_device_enable_hwmods(od);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300708
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300709 od->_state = OMAP_DEVICE_STATE_ENABLED;
710
711 return ret;
712}
713
714/**
715 * omap_device_idle - idle an omap_device
716 * @od: struct omap_device * to idle
717 *
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700718 * Idle omap_device @od. Device drivers call this function indirectly
719 * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300720 * currently enabled, or passes along the return value of
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700721 * _omap_device_idle_hwmods().
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300722 */
723int omap_device_idle(struct platform_device *pdev)
724{
725 int ret;
726 struct omap_device *od;
727
Kevin Hilman8f0d69d2011-07-09 19:15:20 -0600728 od = to_omap_device(pdev);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300729
730 if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
Kevin Hilman49882c92011-07-21 09:58:36 -0700731 dev_warn(&pdev->dev,
732 "omap_device: %s() called from invalid state %d\n",
733 __func__, od->_state);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300734 return -EINVAL;
735 }
736
Paul Walmsleyc1d1cd52013-01-26 00:48:53 -0700737 ret = _omap_device_idle_hwmods(od);
Paul Walmsleyb04b65a2009-09-03 20:14:05 +0300738
739 od->_state = OMAP_DEVICE_STATE_IDLE;
740
741 return ret;
742}
743
744/**
Omar Ramirez Luna8bb9fde2012-09-23 17:28:18 -0600745 * omap_device_assert_hardreset - set a device's hardreset line
746 * @pdev: struct platform_device * to reset
747 * @name: const char * name of the reset line
748 *
749 * Set the hardreset line identified by @name on the IP blocks
750 * associated with the hwmods backing the platform_device @pdev. All
751 * of the hwmods associated with @pdev must have the same hardreset
752 * line linked to them for this to work. Passes along the return value
753 * of omap_hwmod_assert_hardreset() in the event of any failure, or
754 * returns 0 upon success.
755 */
756int omap_device_assert_hardreset(struct platform_device *pdev, const char *name)
757{
758 struct omap_device *od = to_omap_device(pdev);
759 int ret = 0;
760 int i;
761
762 for (i = 0; i < od->hwmods_cnt; i++) {
763 ret = omap_hwmod_assert_hardreset(od->hwmods[i], name);
764 if (ret)
765 break;
766 }
767
768 return ret;
769}
770
771/**
772 * omap_device_deassert_hardreset - release a device's hardreset line
773 * @pdev: struct platform_device * to reset
774 * @name: const char * name of the reset line
775 *
776 * Release the hardreset line identified by @name on the IP blocks
777 * associated with the hwmods backing the platform_device @pdev. All
778 * of the hwmods associated with @pdev must have the same hardreset
779 * line linked to them for this to work. Passes along the return
780 * value of omap_hwmod_deassert_hardreset() in the event of any
781 * failure, or returns 0 upon success.
782 */
783int omap_device_deassert_hardreset(struct platform_device *pdev,
784 const char *name)
785{
786 struct omap_device *od = to_omap_device(pdev);
787 int ret = 0;
788 int i;
789
790 for (i = 0; i < od->hwmods_cnt; i++) {
791 ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
792 if (ret)
793 break;
794 }
795
796 return ret;
797}
798
799/**
Nishanth Menon1f8a7d52011-07-27 15:02:32 -0500800 * omap_device_get_by_hwmod_name() - convert a hwmod name to
801 * device pointer.
802 * @oh_name: name of the hwmod device
803 *
804 * Returns back a struct device * pointer associated with a hwmod
805 * device represented by a hwmod_name
806 */
807struct device *omap_device_get_by_hwmod_name(const char *oh_name)
808{
809 struct omap_hwmod *oh;
810
811 if (!oh_name) {
812 WARN(1, "%s: no hwmod name!\n", __func__);
813 return ERR_PTR(-EINVAL);
814 }
815
816 oh = omap_hwmod_lookup(oh_name);
817 if (IS_ERR_OR_NULL(oh)) {
818 WARN(1, "%s: no hwmod for %s\n", __func__,
819 oh_name);
820 return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV);
821 }
822 if (IS_ERR_OR_NULL(oh->od)) {
823 WARN(1, "%s: no omap_device for %s\n", __func__,
824 oh_name);
825 return ERR_PTR(oh->od ? PTR_ERR(oh->od) : -ENODEV);
826 }
827
828 if (IS_ERR_OR_NULL(oh->od->pdev))
829 return ERR_PTR(oh->od->pdev ? PTR_ERR(oh->od->pdev) : -ENODEV);
830
831 return &oh->od->pdev->dev;
832}
Kevin Hilman0d5e8252010-08-23 08:10:55 -0700833
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200834static struct notifier_block platform_nb = {
835 .notifier_call = _omap_device_notifier_call,
836};
837
Kevin Hilman0d5e8252010-08-23 08:10:55 -0700838static int __init omap_device_init(void)
839{
Benoit Coussondc2d07e2011-08-10 13:32:08 +0200840 bus_register_notifier(&platform_bus_type, &platform_nb);
Kevin Hilman3ec2dec2012-02-15 11:47:45 -0800841 return 0;
Kevin Hilman0d5e8252010-08-23 08:10:55 -0700842}
843core_initcall(omap_device_init);
Kevin Hilman9634c8d2012-07-10 15:06:11 -0700844
845/**
846 * omap_device_late_idle - idle devices without drivers
847 * @dev: struct device * associated with omap_device
848 * @data: unused
849 *
850 * Check the driver bound status of this device, and idle it
851 * if there is no driver attached.
852 */
853static int __init omap_device_late_idle(struct device *dev, void *data)
854{
855 struct platform_device *pdev = to_platform_device(dev);
856 struct omap_device *od = to_omap_device(pdev);
857
858 if (!od)
859 return 0;
860
861 /*
862 * If omap_device state is enabled, but has no driver bound,
863 * idle it.
864 */
865 if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
866 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
867 dev_warn(dev, "%s: enabled but no driver. Idling\n",
868 __func__);
869 omap_device_idle(pdev);
870 }
871 }
872
873 return 0;
874}
875
876static int __init omap_device_late_init(void)
877{
878 bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
879 return 0;
880}
881late_initcall(omap_device_late_init);