Files
BPI-CM9-Linux/aml-comp/kernel/aml-6.12/common_drivers/drivers/pio/pio.c
T

202 lines
4.5 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2025 Amlogic, Inc. All rights reserved.
*/
#define MESON_PIO_NAME "meson_pio"
#include <linux/amlogic/pio/meson_pio.h>
static struct pio_hw *s_pio;
struct pio_hw *pio_get_instance(u32 instance)
{
return s_pio;
}
static struct regmap_config meson_pio_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static inline int meson_pio_mmio(struct platform_device *pdev, struct pio_hw *pio)
{
resource_size_t size;
const char *name = NULL;
int ret = 0;
pio->reg = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, &size);
if (IS_ERR(pio->reg))
return PTR_ERR(pio->reg);
ret = of_property_read_string_index(pdev->dev.of_node, "reg-names", 0, &name);
if (ret)
return ret;
meson_pio_regmap_config.max_register = size - 4;
meson_pio_regmap_config.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn-%s",
pdev->dev.of_node, name);
if (!meson_pio_regmap_config.name)
return -ENOMEM;
pio->regmap = devm_regmap_init_mmio(&pdev->dev, pio->reg, &meson_pio_regmap_config);
if (IS_ERR(pio->regmap))
return PTR_ERR(pio->regmap);
return 0;
}
static inline int meson_pio_irq_parser(struct device_node *node, struct pio_hw *pio)
{
int ret = 0;
int i;
for (i = 0; i < PIO_IRQ_NUM; i++) {
ret = of_irq_get(node, i);
if (ret < 0)
return ret;
pio->irq[i] = ret;
}
return ret;
}
static inline int meson_pio_dma_init(struct pio_hw *pio, struct platform_device *pdev)
{
char chan_name[4];
int ret = 0;
int i;
struct pio_dma *dma;
dma = devm_kmalloc_array(&pdev->dev, NUM_PIO_STATE_MACHINES * 2,
sizeof(struct pio_dma), GFP_KERNEL | __GFP_ZERO);
if (!dma)
return -ENOMEM;
for (i = 0; i < NUM_PIO_STATE_MACHINES; i++) {
pio->dma_tx[i] = &dma[i];
pio->dma_rx[i] = &dma[NUM_PIO_STATE_MACHINES + i];
sprintf(chan_name, "tx%d", i);
pio->dma_tx[i]->chan = dma_request_chan(&pdev->dev, chan_name);
if (IS_ERR(pio->dma_tx[i]->chan)) {
ret = PTR_ERR(pio->dma_tx[i]->chan);
dev_err(&pdev->dev, "can't request DMA tx channel %s, %d\n",
chan_name, ret);
ret = -ENOENT;
goto rq_failed;
}
pio->dma_tx[i]->dma_transfer_dir = DMA_MEM_TO_DEV;
pio->dma_tx[i]->dma_data_dir = DMA_TO_DEVICE;
pio->dma_tx[i]->pio = pio;
pio->dma_tx[i]->enable = true;
init_completion(&pio->dma_tx[i]->dma_complete);
sprintf(chan_name, "rx%d", i);
pio->dma_rx[i]->chan = dma_request_chan(&pdev->dev, chan_name);
if (IS_ERR(pio->dma_rx[i]->chan)) {
ret = PTR_ERR(pio->dma_rx[i]->chan);
dev_err(&pdev->dev, "can't request DMA rx channel %s,%d\n",
chan_name, ret);
ret = -ENOENT;
goto rq_failed;
}
pio->dma_rx[i]->dma_transfer_dir = DMA_DEV_TO_MEM;
pio->dma_rx[i]->dma_data_dir = DMA_FROM_DEVICE;
pio->dma_rx[i]->pio = pio;
pio->dma_rx[i]->enable = true;
init_completion(&pio->dma_rx[i]->dma_complete);
}
pio->has_dma = true;
return 0;
rq_failed:
devm_kfree(&pdev->dev, dma);
for (i = 0; i < NUM_PIO_STATE_MACHINES; i++) {
if (pio->dma_rx[i])
pio->dma_rx[i] = NULL;
if (pio->dma_tx[i])
pio->dma_tx[i] = NULL;
}
return ret;
}
static int meson_pio_probe(struct platform_device *pdev)
{
struct pio_hw *pio;
int ret = 0;
u64 clk_rate;
pio = devm_kzalloc(&pdev->dev, sizeof(*pio), GFP_KERNEL);
if (!pio)
return -ENOMEM;
pio->clk = devm_clk_get(&pdev->dev, "pio_clk");
if (IS_ERR(pio->clk)) {
dev_err(&pdev->dev, "Can't find pio clk!\n");
return PTR_ERR(pio->clk);
}
ret = clk_prepare_enable(pio->clk);
if (ret) {
dev_err(&pdev->dev, "clk enable failed\n");
return ret;
}
clk_rate = clk_get_rate(pio->clk);
pio->clk_rate = clk_rate;
platform_set_drvdata(pdev, pio);
pio->pdev = pdev;
/* regmap mmio */
ret = meson_pio_mmio(pdev, pio);
if (ret)
return ret;
mutex_init(&pio->lock);
ret = of_property_read_u8(pdev->dev.of_node, "amlogic,pio_version", &pio->version);
if (ret < 0)
pio->version = 0;
ret = meson_pio_irq_parser(pdev->dev.of_node, pio);
if (ret < 0)
return ret;
ret = of_property_read_bool(pdev->dev.of_node, "amlogic,support-dma");
if (ret)
if (meson_pio_dma_init(pio, pdev) < 0)
pr_info("DMA request failed or not support !\n");
#if IS_ENABLED(CONFIG_AMLOGIC_PIO_TEST)
ret = pio_class_register();
if (ret)
return ret;
#endif
s_pio = pio;
return 0;
}
static const struct of_device_id meson_pio_dt_match[] = {
{
.compatible = "amlogic,pio",
},
{}
};
static struct platform_driver meson_pio_driver = {
.probe = meson_pio_probe,
.driver = {
.name = MESON_PIO_NAME,
.of_match_table = meson_pio_dt_match,
},
};
module_platform_driver(meson_pio_driver);
MODULE_LICENSE("GPL v2");