123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-02-25 GuEe-GUI the first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <ioremap.h>
- #include <drivers/ofw_io.h>
- #include <drivers/syscon.h>
- #include <drivers/core/dm.h>
- #include <drivers/platform.h>
- static RT_DEFINE_SPINLOCK(_syscon_nodes_lock);
- static rt_list_t _syscon_nodes = RT_LIST_OBJECT_INIT(_syscon_nodes);
- rt_err_t rt_syscon_read(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t *out_val)
- {
- if (offset < syscon->iomem_size)
- {
- rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
- *out_val = HWREG32(syscon->iomem_base + offset);
- rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
- return RT_EOK;
- }
- else
- {
- return -RT_EINVAL;
- }
- }
- rt_err_t rt_syscon_write(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t val)
- {
- if (offset < syscon->iomem_size)
- {
- rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
- HWREG32(syscon->iomem_base + offset) = val;
- rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
- return RT_EOK;
- }
- else
- {
- return -RT_EINVAL;
- }
- }
- rt_err_t rt_syscon_update_bits(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t mask, rt_uint32_t val)
- {
- rt_err_t err;
- rt_ubase_t level = rt_spin_lock_irqsave(&syscon->rw_lock);
- if (offset < syscon->iomem_size)
- {
- rt_uint32_t old_val = HWREG32(syscon->iomem_base + offset);
- old_val &= ~mask;
- HWREG32(syscon->iomem_base + offset) = old_val | val;
- err = RT_EOK;
- }
- else
- {
- err = -RT_EINVAL;
- }
- rt_spin_unlock_irqrestore(&syscon->rw_lock, level);
- return err;
- }
- static rt_err_t syscon_probe(struct rt_platform_device *pdev);
- struct rt_syscon *rt_syscon_find_by_ofw_node(struct rt_ofw_node *np)
- {
- rt_ubase_t level;
- struct rt_syscon *syscon = RT_NULL, *syscon_tmp;
- struct rt_platform_device syscon_pdev;
- if (!np)
- {
- goto _exit;
- }
- level = rt_spin_lock_irqsave(&_syscon_nodes_lock);
- /* ofw_data is not safety */
- rt_list_for_each_entry(syscon_tmp, &_syscon_nodes, list)
- {
- if (syscon_tmp->np == np)
- {
- syscon = syscon_tmp;
- break;
- }
- }
- rt_spin_unlock_irqrestore(&_syscon_nodes_lock, level);
- if (syscon)
- {
- goto _exit;
- }
- /* Not found, try probe this node */
- if (!rt_ofw_node_is_compatible(np, "syscon") &&
- !rt_ofw_node_is_compatible(np, "simple-mfd"))
- {
- goto _exit;
- }
- syscon_pdev.parent.ofw_node = np;
- if (!syscon_probe(&syscon_pdev))
- {
- syscon = rt_ofw_data(np);
- }
- _exit:
- return syscon;
- }
- struct rt_syscon *rt_syscon_find_by_ofw_compatible(const char *compatible)
- {
- struct rt_syscon *syscon = RT_NULL;
- struct rt_ofw_node *syscon_np = rt_ofw_find_node_by_compatible(RT_NULL, compatible);
- if (syscon_np)
- {
- syscon = rt_syscon_find_by_ofw_node(syscon_np);
- rt_ofw_node_put(syscon_np);
- }
- return syscon;
- }
- struct rt_syscon *rt_syscon_find_by_ofw_phandle(struct rt_ofw_node *np, const char *propname)
- {
- struct rt_syscon *syscon = RT_NULL;
- struct rt_ofw_node *syscon_np = rt_ofw_parse_phandle(np, propname, 0);
- if (syscon_np)
- {
- syscon = rt_syscon_find_by_ofw_node(syscon_np);
- rt_ofw_node_put(syscon_np);
- }
- return syscon;
- }
- static rt_err_t syscon_probe(struct rt_platform_device *pdev)
- {
- rt_err_t err;
- rt_ubase_t level;
- struct rt_ofw_node *np;
- rt_uint64_t iomem_range[2];
- struct rt_syscon *syscon = rt_calloc(1, sizeof(*syscon));
- if (!syscon)
- {
- return -RT_ENOMEM;
- }
- np = pdev->parent.ofw_node;
- if ((err = rt_ofw_get_address(np, 0, &iomem_range[0], &iomem_range[1])))
- {
- goto _fail;
- }
- syscon->iomem_size = (rt_size_t)iomem_range[1];
- syscon->iomem_base = rt_ioremap((void *)iomem_range[0], syscon->iomem_size);
- if (!syscon->iomem_base)
- {
- goto _fail;
- }
- rt_list_init(&syscon->list);
- level = rt_spin_lock_irqsave(&_syscon_nodes_lock);
- rt_list_insert_after(&_syscon_nodes, &syscon->list);
- rt_spin_unlock_irqrestore(&_syscon_nodes_lock, level);
- rt_spin_lock_init(&syscon->rw_lock);
- pdev->parent.user_data = syscon;
- syscon->np = pdev->parent.ofw_node;
- rt_ofw_data(np) = syscon;
- return RT_EOK;
- _fail:
- rt_free(syscon);
- return err;
- }
- static rt_err_t syscon_remove(struct rt_platform_device *pdev)
- {
- struct rt_syscon *syscon = pdev->parent.user_data;
- rt_iounmap(syscon->iomem_base);
- rt_free(syscon);
- return RT_EOK;
- }
- static const struct rt_ofw_node_id syscon_ofw_ids[] =
- {
- { .compatible = "syscon" },
- { /* sentinel */ }
- };
- static struct rt_platform_driver syscon_driver =
- {
- .name = "mfd-syscon",
- .ids = syscon_ofw_ids,
- .probe = syscon_probe,
- .remove = syscon_remove,
- };
- static int syscon_drv_register(void)
- {
- rt_platform_driver_register(&syscon_driver);
- return 0;
- }
- INIT_SUBSYS_EXPORT(syscon_drv_register);
|