123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Copyright (C) 2021 Alibaba Group Holding Limited.
- */
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/io.h>
- #include <linux/clk.h>
- #include <linux/completion.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
- #include <linux/regulator/consumer.h>
- #include <linux/of_platform.h>
- #include <linux/err.h>
- #include <dt-bindings/soc/thead,light-iopmp.h>
- #define LIGHT_PMP_MISC_CTRL 0x04
- #define LIGHT_PMP_DUMMY_ADDR 0x08
- #define LIGHT_PMP_PAGE_LOCK0 0x40
- #define LIGHT_PMP_ATTR_CFG0 0x80
- #define LIGHT_DEFAULT_PMP_ATTR_CFG 0xc0
- #define LIGHT_PMP_REGION0_SADDR 0x280
- #define LIGHT_PMP_REGION0_EADDR 0x284
- #define LIGHT_PMP_PAGE_LOCK0_REGIONS 0xFFFF
- #define LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG BIT(16)
- #define LIGHT_PMP_PAGE_LOCK0_BYPASS_EN BIT(17)
- #define LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR BIT(18)
- #define LIGHT_IOPMP_REGION_NUM 16
- #define LIGHT_IOPMP_ATTR_CFG_DEFAULT 0xFFFFFFFF
- #define LIGHT_IOPMP_DUMMY_ADDR 0x800000
- #define LIGHT_IOPMP_CTRL_BYPASS 0xFF000000
- struct light_iopmp_entry {
- u32 reg_start[LIGHT_IOPMP_REGION_NUM];
- u32 reg_end[LIGHT_IOPMP_REGION_NUM];
- u32 entry_valid_num;
- };
- struct light_iopmp_cur_sys_entry {
- int iopmp_type;
- u32 start_addr;
- u32 end_addr;
- u32 attr;
- int lock;
- };
- struct light_iopmp_info {
- struct device *dev;
- int entries;
- struct light_iopmp_list *iopmp_list;
- struct light_iopmp_cur_sys_entry cur_entry;
- struct light_iopmp_entry iopmp_entry[];
- };
- static struct light_iopmp_list {
- int iopmp_type;
- resource_size_t offset;
- void __iomem *base;
- } light_iopmp_lists[] = {
- {IOPMP_EMMC, 0xFFFC028000, NULL},
- {IOPMP_SDIO0, 0xFFFC029000, NULL},
- {IOPMP_SDIO1, 0xFFFC02A000, NULL},
- {IOPMP_USB0, 0xFFFC02E000, NULL},
- {IOPMP_AO, 0xFFFFC21000, NULL},
- {IOPMP_AUD, 0xFFFFC22000, NULL},
- {IOPMP_CHIP_DBG, 0xFFFFC37000, NULL},
- {IOPMP_EIP120I, 0xFFFF220000, NULL},
- {IOPMP_EIP120II, 0xFFFF230000, NULL},
- {IOPMP_EIP120III, 0xFFFF240000, NULL},
- {IOPMP_ISP0, 0xFFF4080000, NULL},
- {IOPMP_ISP1, 0xFFF4081000, NULL},
- {IOPMP_DW200, 0xFFF4082000, NULL},
- {IOPMP_VIPRE, 0xFFF4083000, NULL},
- {IOPMP_VENC, 0xFFFCC60000, NULL},
- {IOPMP_VDEC, 0xFFFCC61000, NULL},
- {IOPMP_G2D, 0xFFFCC62000, NULL},
- {IOPMP_FCE, 0xFFFCC63000, NULL},
- {IOPMP_NPU, 0xFFFF01C000, NULL},
- {IOPMP0_DPU, 0xFFFF520000, NULL},
- {IOPMP1_DPU, 0xFFFF521000, NULL},
- {IOPMP_GPU, 0xFFFF522000, NULL},
- {IOPMP_GMAC1, 0xFFFC001000, NULL},
- {IOPMP_GMAC2, 0xFFFC002000, NULL},
- {IOPMP_DMAC, 0xFFFFC20000, NULL},
- {IOPMP_TEE_DMAC, 0xFFFF250000, NULL},
- {IOPMP_DSP0, 0xFFFF058000, NULL},
- {IOPMP_DSP1, 0xFFFF059000, NULL},
- };
- static const struct light_iopmp_driver_data {
- struct light_iopmp_list *iopmp_list;
- } light_iopmp_data = {
- .iopmp_list = light_iopmp_lists,
- };
- static int light_iopmp_get_entries(struct light_iopmp_list *match)
- {
- if (match == light_iopmp_lists)
- return ARRAY_SIZE(light_iopmp_lists);
- return 0;
- }
- static int light_iopmp_get_type(struct light_iopmp_info *info, struct device_node *entry_np)
- {
- int entry_size = info->entries;
- struct light_iopmp_list *match = info->iopmp_list;
- unsigned long type;
- if (kstrtoul(entry_np->name, 0, &type))
- return -EINVAL;
- if (type < match[0].iopmp_type || type > match[entry_size - 1].iopmp_type)
- return -EINVAL;
- return type;
- }
- static bool light_iopmp_type_valid(struct light_iopmp_info *info, int tap)
- {
- int entry_size = info->entries;
- struct light_iopmp_list *match = info->iopmp_list;
- if (tap < match[0].iopmp_type || tap > match[entry_size - 1].iopmp_type)
- return false;
- return true;
- }
- static void light_iopmp_set_attr_bypass(struct light_iopmp_info *info, int type)
- {
- void __iomem *regs;
- u32 val;
- if (!info->iopmp_list[type].base) {
- regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
- if (!regs) {
- dev_err(info->dev, "ioremap failed\n");
- return;
- }
- info->iopmp_list[type].base = regs;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- if (val & LIGHT_PMP_PAGE_LOCK0_BYPASS_EN) {
- dev_info(info->dev, "iopmp bypass_en is already locked, ignore the tap[%d] setting\n", type);
- return;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- val |= LIGHT_IOPMP_CTRL_BYPASS;
- writel(val, info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- /* lock the iopmp */
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- val |= LIGHT_PMP_PAGE_LOCK0_BYPASS_EN;
- writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- }
- static void light_iopmp_set_attr_default(struct light_iopmp_info *info, int type, int attr)
- {
- void __iomem *regs;
- u32 val;
- if (!info->iopmp_list[type].base) {
- regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
- if (!regs) {
- dev_err(info->dev, "ioremap failed\n");
- return;
- }
- info->iopmp_list[type].base = regs;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- if (val & LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG) {
- dev_info(info->dev, "iopmp default cfg is already locked, ignore the tap[%d] setting\n", type);
- return;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- if (val & LIGHT_IOPMP_CTRL_BYPASS) {
- dev_info(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
- return;
- }
- writel(attr, info->iopmp_list[type].base + LIGHT_DEFAULT_PMP_ATTR_CFG);
- /* lock the iopmp */
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- val |= LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG;
- writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- }
- static void light_iopmp_set_attr(struct light_iopmp_info *info, int type, int attr,
- int dummy_slave, struct light_iopmp_entry *entry)
- {
- void __iomem *regs;
- bool dummy_slave_lock = false;
- u32 val;
- int i;
- if (!info->iopmp_list[type].base) {
- regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
- if (!regs) {
- dev_err(info->dev, "ioremap failed\n");
- return;
- }
- info->iopmp_list[type].base = regs;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- if (val & LIGHT_PMP_PAGE_LOCK0_REGIONS) {
- dev_info(info->dev, "iopmp regions cfg is already locked, ignore the tap[%d] setting\n", type);
- return;
- }
- if (val & LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR)
- dummy_slave_lock = true;
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- if (val & LIGHT_IOPMP_CTRL_BYPASS) {
- dev_info(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
- return;
- }
- for (i = 0; i < entry->entry_valid_num; i++) {
- writel(entry->reg_start[i],
- info->iopmp_list[type].base + LIGHT_PMP_REGION0_SADDR + (i << 3));
- writel(entry->reg_end[i],
- info->iopmp_list[type].base + LIGHT_PMP_REGION0_EADDR + (i << 3));
- writel(attr, info->iopmp_list[type].base + LIGHT_PMP_ATTR_CFG0 + (i << 2));
- }
- if (!dummy_slave_lock)
- writel(dummy_slave, info->iopmp_list[type].base + LIGHT_PMP_DUMMY_ADDR);
- /* lock the iopmp */
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- val |= LIGHT_PMP_PAGE_LOCK0_REGIONS | LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR;
- writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- }
- static int light_iopmp_sys_set(struct light_iopmp_info *info)
- {
- void __iomem *regs;
- int type = info->cur_entry.iopmp_type;
- bool dummy_slave_lock = false;
- u32 val;
- if (!info->iopmp_list[type].base) {
- regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
- if (!regs) {
- dev_err(info->dev, "ioremap failed\n");
- return -ENOMEM;
- }
- info->iopmp_list[type].base = regs;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- if (val & LIGHT_IOPMP_CTRL_BYPASS) {
- dev_err(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
- return -EINVAL;
- }
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- if (val & LIGHT_PMP_PAGE_LOCK0_REGIONS) {
- dev_err(info->dev, "iopmp regions cfg is already locked, ignore the tap[%d] setting\n", type);
- return -EINVAL;
- }
- if (val & LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR)
- dummy_slave_lock = true;
- val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
- if (val & LIGHT_IOPMP_CTRL_BYPASS) {
- dev_err(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
- return -EINVAL;
- }
- /* set one region from userspace's config */
- writel(info->cur_entry.start_addr,
- info->iopmp_list[type].base + LIGHT_PMP_REGION0_SADDR);
- writel(info->cur_entry.end_addr,
- info->iopmp_list[type].base + LIGHT_PMP_REGION0_EADDR);
- writel(info->cur_entry.attr, info->iopmp_list[type].base + LIGHT_PMP_ATTR_CFG0);
- if (!dummy_slave_lock)
- writel(LIGHT_IOPMP_DUMMY_ADDR, info->iopmp_list[type].base + LIGHT_PMP_DUMMY_ADDR);
- /* lock the iopmp */
- if (info->cur_entry.lock) {
- val = LIGHT_PMP_PAGE_LOCK0_REGIONS | LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG |
- LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR | LIGHT_PMP_PAGE_LOCK0_BYPASS_EN;
- writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
- }
- return 0;
- }
- static ssize_t light_iopmp_tap_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- ssize_t ret;
- ret = sprintf(buf, "%d\n", info->cur_entry.iopmp_type);
- return ret;
- }
- static ssize_t light_iopmp_start_addr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- ssize_t ret;
- ret = sprintf(buf, "0x%x\n", info->cur_entry.start_addr);
- return ret;
- }
- static ssize_t light_iopmp_end_addr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- ssize_t ret;
- ret = sprintf(buf, "0x%x\n", info->cur_entry.end_addr);
- return ret;
- }
- static ssize_t light_iopmp_attr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- ssize_t ret;
- ret = sprintf(buf, "0x%x\n", info->cur_entry.attr);
- return ret;
- }
- static ssize_t light_iopmp_lock_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- ssize_t ret;
- ret = sprintf(buf, "%s\n", info->cur_entry.lock ? "locked" : "no lock");
- return ret;
- }
- static ssize_t light_iopmp_tap_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- if (light_iopmp_type_valid(info, (int)val))
- info->cur_entry.iopmp_type = val;
- else
- dev_err(dev, "invalid tap value\n");
- return count;
- }
- static ssize_t light_iopmp_start_addr_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- info->cur_entry.start_addr = (u32)val;
- return count;
- }
- static ssize_t light_iopmp_end_addr_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- if (!val)
- return -EINVAL;
- info->cur_entry.end_addr = (u32)val;
- return count;
- }
- static ssize_t light_iopmp_attr_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- info->cur_entry.attr = (u32)val;
- return count;
- }
- static ssize_t light_iopmp_lock_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- info->cur_entry.lock = (int)val;
- return count;
- }
- static ssize_t light_iopmp_set_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct light_iopmp_info *info = platform_get_drvdata(pdev);
- unsigned long val;
- int ret;
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
- if (!val)
- return count;
- if (!light_iopmp_type_valid(info, info->cur_entry.iopmp_type)) {
- dev_err(dev, "invalid iopmp tap ID\n");
- return -EINVAL;
- }
- if (info->cur_entry.end_addr <= info->cur_entry.start_addr) {
- dev_err(dev, "invalid end_addr/start_addr setting\n");
- return -EINVAL;
- }
- ret = light_iopmp_sys_set(info);
- if (ret)
- return -EINVAL;
- return count;
- }
- static DEVICE_ATTR(light_iopmp_tap, 0644, light_iopmp_tap_show, light_iopmp_tap_store);
- static DEVICE_ATTR(light_iopmp_start_addr, 0644, light_iopmp_start_addr_show, light_iopmp_start_addr_store);
- static DEVICE_ATTR(light_iopmp_end_addr, 0644, light_iopmp_end_addr_show, light_iopmp_end_addr_store);
- static DEVICE_ATTR(light_iopmp_attr, 0644, light_iopmp_attr_show, light_iopmp_attr_store);
- static DEVICE_ATTR(light_iopmp_lock, 0644, light_iopmp_lock_show, light_iopmp_lock_store);
- static DEVICE_ATTR(light_iopmp_set, 0644, NULL, light_iopmp_set_store);
- static struct attribute *light_iopmp_sysfs_entries[] = {
- &dev_attr_light_iopmp_tap.attr,
- &dev_attr_light_iopmp_start_addr.attr,
- &dev_attr_light_iopmp_end_addr.attr,
- &dev_attr_light_iopmp_attr.attr,
- &dev_attr_light_iopmp_lock.attr,
- &dev_attr_light_iopmp_set.attr,
- NULL
- };
- static const struct attribute_group dev_attr_light_iopmp_group = {
- .attrs = light_iopmp_sysfs_entries,
- };
- static int light_iopmp_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- const struct light_iopmp_driver_data *drvdata = NULL;
- struct light_iopmp_list *match;
- struct light_iopmp_info *info;
- struct device_node *entry_np;
- int size, entries;
- int ret;
- drvdata = device_get_match_data(dev);
- if (!drvdata) {
- dev_err(dev, "cannot get driver data\n");
- return -ENOENT;
- }
- match = drvdata->iopmp_list;
- entries = light_iopmp_get_entries(match);
- if (entries <= 0)
- return -ENOENT;
- size = sizeof(struct light_iopmp_entry) * entries + sizeof(*info);
- info = devm_kzalloc(dev, size, GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- info->entries = entries;
- info->iopmp_list = match;
- info->dev = dev;
- for_each_child_of_node(dev->of_node, entry_np) {
- int attr = LIGHT_IOPMP_ATTR_CFG_DEFAULT;
- int dummy_slave = LIGHT_IOPMP_DUMMY_ADDR;
- bool is_default_region = false;
- bool bypass_en = false;
- int region_size;
- int type;
- int i = 0, j;
- if (!of_device_is_available(entry_np))
- continue;
- type = light_iopmp_get_type(info, entry_np);
- if (type < 0) {
- dev_err(dev, "invalid iopmp tap:%d\n", type);
- continue;
- }
- ret = of_property_read_u32(entry_np, "attr", &attr);
- if (!ret && (attr == 0))
- attr = LIGHT_IOPMP_ATTR_CFG_DEFAULT;
- ret = of_property_read_u32(entry_np, "dummy_slave", &dummy_slave);
- if (!ret && (dummy_slave == 0))
- dummy_slave = LIGHT_IOPMP_DUMMY_ADDR;
- region_size = of_property_count_elems_of_size(entry_np, "regions", sizeof(u32));
- if (region_size <= 0) {
- is_default_region = of_property_read_bool(entry_np, "is_default_region");
- bypass_en = of_property_read_bool(entry_np, "bypass_en");
- if (!is_default_region && !bypass_en) {
- dev_err(dev, "missing/invalid reg property\n");
- continue;
- }
- /* config the iopmp entry */
- if (bypass_en)
- light_iopmp_set_attr_bypass(info, type);
- else if (is_default_region)
- light_iopmp_set_attr_default(info, type, attr);
- } else {
- region_size >>= 1;
- if (region_size > LIGHT_IOPMP_REGION_NUM) {
- dev_err(dev, "region size is invalid\n");
- continue;
- }
- for (j = 0; j < region_size; j++) {
- ret = of_property_read_u32_index(entry_np, "regions",
- j << 1, &info->iopmp_entry[i].reg_start[j]);
- if (ret)
- break;
- ret = of_property_read_u32_index(entry_np, "regions",
- (j << 1) + 1, &info->iopmp_entry[i].reg_end[j]);
- if (ret)
- break;
- /* check the region valid, otherwise drop the iopmp setting */
- if (j && info->iopmp_entry[i].reg_end[j - 1] > info->iopmp_entry[i].reg_start[j])
- break;
- }
- if (j == region_size) {
- info->iopmp_entry[i].entry_valid_num = region_size;
- /* config the iopmp entry */
- light_iopmp_set_attr(info, type, attr, dummy_slave, &info->iopmp_entry[i]);
- }
- }
- i++;
- }
- /* init the cur entry config */
- info->cur_entry.iopmp_type = -1;
- info->cur_entry.start_addr = 0;
- info->cur_entry.end_addr = 0;
- info->cur_entry.attr = 0;
- info->cur_entry.lock = false;
- platform_set_drvdata(pdev, info);
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_light_iopmp_group);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create light iopmp debug sysfs.\n");
- return ret;
- }
- return 0;
- }
- static int light_iopmp_remove(struct platform_device *pdev)
- {
- platform_set_drvdata(pdev, NULL);
- return 0;
- }
- static int __maybe_unused light_iopmp_noirq_suspend(struct device *dev)
- {
- /* the iopmp clocks depend on module theirself,
- * we should keep them always enabled in clock's driver
- */
- return 0;
- }
- static int __maybe_unused light_iopmp_noirq_resume(struct device *dev)
- {
- /* TBD: restore IOPMP in noirq stage is too late ?
- * we should restore these registers setting in early arch resume ?
- */
- return 0;
- }
- static const struct dev_pm_ops light_iopmp_pm_ops = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(light_iopmp_noirq_suspend, light_iopmp_noirq_resume)
- };
- static const struct of_device_id light_iopmp_of_match[] = {
- { .compatible = "thead,light-iopmp", .data = &light_iopmp_data},
- {},
- };
- static struct platform_driver light_iopmp_driver = {
- .driver = {
- .name = "light-iopmp",
- .of_match_table = of_match_ptr(light_iopmp_of_match),
- .pm = &light_iopmp_pm_ops,
- },
- .probe = light_iopmp_probe,
- .remove = light_iopmp_remove,
- };
- static int __init light_iopmp_init(void)
- {
- return platform_driver_register(&light_iopmp_driver);
- }
- arch_initcall(light_iopmp_init);
- MODULE_ALIAS("platform:light-iopmp");
- MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>");
- MODULE_DESCRIPTION("Thead Light iopmp driver");
- MODULE_LICENSE("GPL v2");
|