0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/of_address.h>
0013 #include <linux/slab.h>
0014 #include <linux/suspend.h>
0015 #include <linux/kernel.h>
0016 #include <linux/acpi.h>
0017
0018 #define RCPM_WAKEUP_CELL_MAX_SIZE 7
0019
0020 struct rcpm {
0021 unsigned int wakeup_cells;
0022 void __iomem *ippdexpcr_base;
0023 bool little_endian;
0024 };
0025
0026 #define SCFG_SPARECR8 0x051c
0027
0028 static void copy_ippdexpcr1_setting(u32 val)
0029 {
0030 struct device_node *np;
0031 void __iomem *regs;
0032 u32 reg_val;
0033
0034 np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg");
0035 if (!np)
0036 return;
0037
0038 regs = of_iomap(np, 0);
0039 if (!regs)
0040 return;
0041
0042 reg_val = ioread32be(regs + SCFG_SPARECR8);
0043 iowrite32be(val | reg_val, regs + SCFG_SPARECR8);
0044
0045 iounmap(regs);
0046 }
0047
0048
0049
0050
0051
0052
0053
0054 static int rcpm_pm_prepare(struct device *dev)
0055 {
0056 int i, ret, idx;
0057 void __iomem *base;
0058 struct wakeup_source *ws;
0059 struct rcpm *rcpm;
0060 struct device_node *np = dev->of_node;
0061 u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
0062 u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
0063
0064 rcpm = dev_get_drvdata(dev);
0065 if (!rcpm)
0066 return -EINVAL;
0067
0068 base = rcpm->ippdexpcr_base;
0069 idx = wakeup_sources_read_lock();
0070
0071
0072 for_each_wakeup_source(ws) {
0073
0074
0075 if (!ws->dev || !ws->dev->parent)
0076 continue;
0077
0078 ret = device_property_read_u32_array(ws->dev->parent,
0079 "fsl,rcpm-wakeup", value,
0080 rcpm->wakeup_cells + 1);
0081
0082 if (ret)
0083 continue;
0084
0085
0086
0087
0088
0089
0090
0091
0092 if (is_of_node(dev->fwnode))
0093 if (np->phandle != value[0])
0094 continue;
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 for (i = 0; i < rcpm->wakeup_cells; i++)
0105 setting[i] |= value[i + 1];
0106 }
0107
0108 wakeup_sources_read_unlock(idx);
0109
0110
0111 for (i = 0; i < rcpm->wakeup_cells; i++) {
0112 u32 tmp = setting[i];
0113 void __iomem *address = base + i * 4;
0114
0115 if (!tmp)
0116 continue;
0117
0118
0119 if (rcpm->little_endian) {
0120 tmp |= ioread32(address);
0121 iowrite32(tmp, address);
0122 } else {
0123 tmp |= ioread32be(address);
0124 iowrite32be(tmp, address);
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134 if (dev_of_node(dev) && (i == 1))
0135 if (of_device_is_compatible(np, "fsl,ls1021a-rcpm"))
0136 copy_ippdexpcr1_setting(tmp);
0137 }
0138
0139 return 0;
0140 }
0141
0142 static const struct dev_pm_ops rcpm_pm_ops = {
0143 .prepare = rcpm_pm_prepare,
0144 };
0145
0146 static int rcpm_probe(struct platform_device *pdev)
0147 {
0148 struct device *dev = &pdev->dev;
0149 struct rcpm *rcpm;
0150 int ret;
0151
0152 rcpm = devm_kzalloc(dev, sizeof(*rcpm), GFP_KERNEL);
0153 if (!rcpm)
0154 return -ENOMEM;
0155
0156 rcpm->ippdexpcr_base = devm_platform_ioremap_resource(pdev, 0);
0157 if (IS_ERR(rcpm->ippdexpcr_base)) {
0158 ret = PTR_ERR(rcpm->ippdexpcr_base);
0159 return ret;
0160 }
0161
0162 rcpm->little_endian = device_property_read_bool(
0163 &pdev->dev, "little-endian");
0164
0165 ret = device_property_read_u32(&pdev->dev,
0166 "#fsl,rcpm-wakeup-cells", &rcpm->wakeup_cells);
0167 if (ret)
0168 return ret;
0169
0170 dev_set_drvdata(&pdev->dev, rcpm);
0171
0172 return 0;
0173 }
0174
0175 static const struct of_device_id rcpm_of_match[] = {
0176 { .compatible = "fsl,qoriq-rcpm-2.1+", },
0177 {}
0178 };
0179 MODULE_DEVICE_TABLE(of, rcpm_of_match);
0180
0181 #ifdef CONFIG_ACPI
0182 static const struct acpi_device_id rcpm_acpi_ids[] = {
0183 {"NXP0015",},
0184 { }
0185 };
0186 MODULE_DEVICE_TABLE(acpi, rcpm_acpi_ids);
0187 #endif
0188
0189 static struct platform_driver rcpm_driver = {
0190 .driver = {
0191 .name = "rcpm",
0192 .of_match_table = rcpm_of_match,
0193 .acpi_match_table = ACPI_PTR(rcpm_acpi_ids),
0194 .pm = &rcpm_pm_ops,
0195 },
0196 .probe = rcpm_probe,
0197 };
0198
0199 module_platform_driver(rcpm_driver);