1 // SPDX-License-Identifier: GPL-2.0
3 // rcpm.c - Freescale QorIQ RCPM driver
7 // Author: Ran Wang <ran.wang_1@nxp.com>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/of_address.h>
13 #include <linux/slab.h>
14 #include <linux/suspend.h>
15 #include <linux/kernel.h>
17 #define RCPM_WAKEUP_CELL_MAX_SIZE 7
20 unsigned int wakeup_cells
;
21 void __iomem
*ippdexpcr_base
;
26 * rcpm_pm_prepare - performs device-level tasks associated with power
27 * management, such as programming related to the wakeup source control.
28 * @dev: Device to handle.
31 static int rcpm_pm_prepare(struct device
*dev
)
35 struct wakeup_source
*ws
;
37 struct device_node
*np
= dev
->of_node
;
38 u32 value
[RCPM_WAKEUP_CELL_MAX_SIZE
+ 1];
39 u32 setting
[RCPM_WAKEUP_CELL_MAX_SIZE
] = {0};
41 rcpm
= dev_get_drvdata(dev
);
45 base
= rcpm
->ippdexpcr_base
;
46 idx
= wakeup_sources_read_lock();
48 /* Begin with first registered wakeup source */
49 for_each_wakeup_source(ws
) {
51 /* skip object which is not attached to device */
52 if (!ws
->dev
|| !ws
->dev
->parent
)
55 ret
= device_property_read_u32_array(ws
->dev
->parent
,
56 "fsl,rcpm-wakeup", value
,
57 rcpm
->wakeup_cells
+ 1);
59 /* Wakeup source should refer to current rcpm device */
60 if (ret
|| (np
->phandle
!= value
[0]))
63 /* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
64 * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
65 * of wakeup source IP contains an integer array: <phandle to
66 * RCPM node, IPPDEXPCR0 setting, IPPDEXPCR1 setting,
67 * IPPDEXPCR2 setting, etc>.
69 * So we will go thought them to collect setting data.
71 for (i
= 0; i
< rcpm
->wakeup_cells
; i
++)
72 setting
[i
] |= value
[i
+ 1];
75 wakeup_sources_read_unlock(idx
);
77 /* Program all IPPDEXPCRn once */
78 for (i
= 0; i
< rcpm
->wakeup_cells
; i
++) {
80 void __iomem
*address
= base
+ i
* 4;
85 /* We can only OR related bits */
86 if (rcpm
->little_endian
) {
87 tmp
|= ioread32(address
);
88 iowrite32(tmp
, address
);
90 tmp
|= ioread32be(address
);
91 iowrite32be(tmp
, address
);
98 static const struct dev_pm_ops rcpm_pm_ops
= {
99 .prepare
= rcpm_pm_prepare
,
102 static int rcpm_probe(struct platform_device
*pdev
)
104 struct device
*dev
= &pdev
->dev
;
109 rcpm
= devm_kzalloc(dev
, sizeof(*rcpm
), GFP_KERNEL
);
113 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
117 rcpm
->ippdexpcr_base
= devm_ioremap_resource(&pdev
->dev
, r
);
118 if (IS_ERR(rcpm
->ippdexpcr_base
)) {
119 ret
= PTR_ERR(rcpm
->ippdexpcr_base
);
123 rcpm
->little_endian
= device_property_read_bool(
124 &pdev
->dev
, "little-endian");
126 ret
= device_property_read_u32(&pdev
->dev
,
127 "#fsl,rcpm-wakeup-cells", &rcpm
->wakeup_cells
);
131 dev_set_drvdata(&pdev
->dev
, rcpm
);
136 static const struct of_device_id rcpm_of_match
[] = {
137 { .compatible
= "fsl,qoriq-rcpm-2.1+", },
140 MODULE_DEVICE_TABLE(of
, rcpm_of_match
);
142 static struct platform_driver rcpm_driver
= {
145 .of_match_table
= rcpm_of_match
,
151 module_platform_driver(rcpm_driver
);