You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
mfd: Add driver for Rockchip Flexbus
Change-Id: I14529b18c2adb06bf71cd669b75f5f277e727637 Signed-off-by: Wesley Yao <wesley.yao@rock-chips.com>
This commit is contained in:
@@ -1304,6 +1304,14 @@ config MFD_RK1000
|
||||
source "drivers/mfd/display-serdes/Kconfig"
|
||||
source "drivers/mfd/rkx110_x120/Kconfig"
|
||||
|
||||
config MFD_ROCKCHIP_FLEXBUS
|
||||
tristate "Rockchip Flexbus"
|
||||
depends on ARCH_ROCKCHIP
|
||||
depends on OF
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this to get support for Rockchip Flexbus.
|
||||
|
||||
config MFD_RN5T618
|
||||
tristate "Ricoh RN5T567/618 PMIC"
|
||||
depends on I2C
|
||||
|
||||
@@ -234,6 +234,7 @@ obj-$(CONFIG_MFD_RK806_I2C) += rk806-i2c.o
|
||||
obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o
|
||||
obj-$(CONFIG_MFD_RK808) += rk808.o
|
||||
obj-$(CONFIG_MFD_RK1000) += rk1000-core.o
|
||||
obj-$(CONFIG_MFD_ROCKCHIP_FLEXBUS) += rockchip-flexbus.o
|
||||
obj-$(CONFIG_MFD_SERDES_DISPLAY) += display-serdes/
|
||||
obj-y += rkx110_x120/
|
||||
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
|
||||
|
||||
209
drivers/mfd/rockchip-flexbus.c
Normal file
209
drivers/mfd/rockchip-flexbus.c
Normal file
@@ -0,0 +1,209 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Driver for Rockchip Flexbus
|
||||
*
|
||||
* Copyright (C) 2024 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <dt-bindings/mfd/rockchip-flexbus.h>
|
||||
#include <linux/mfd/rockchip-flexbus.h>
|
||||
|
||||
enum rockchip_flexbus_tx_rx_mode {
|
||||
FLEXBUS_TX_AND_RX = 0x0,
|
||||
FLEXBUS_TX_ONLY = 0x1,
|
||||
FLEXBUS_RX_ONLY = 0x2,
|
||||
FLEXBUS_TX_THEN_RX = 0x3,
|
||||
};
|
||||
|
||||
unsigned int rockchip_flexbus_readl(struct rockchip_flexbus *rkfb, unsigned int reg)
|
||||
{
|
||||
return readl_relaxed(rkfb->base + reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_flexbus_readl);
|
||||
|
||||
void rockchip_flexbus_writel(struct rockchip_flexbus *rkfb, unsigned int reg, unsigned int val)
|
||||
{
|
||||
writel_relaxed(val, rkfb->base + reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_flexbus_writel);
|
||||
|
||||
void rockchip_flexbus_clrbits(struct rockchip_flexbus *rkfb, unsigned int reg, unsigned int clr_val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
|
||||
reg_val = rockchip_flexbus_readl(rkfb, reg);
|
||||
reg_val &= ~(clr_val);
|
||||
rockchip_flexbus_writel(rkfb, reg, reg_val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_flexbus_clrbits);
|
||||
|
||||
void rockchip_flexbus_setbits(struct rockchip_flexbus *rkfb, unsigned int reg, unsigned int set_val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
|
||||
reg_val = rockchip_flexbus_readl(rkfb, reg);
|
||||
reg_val |= set_val;
|
||||
rockchip_flexbus_writel(rkfb, reg, reg_val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_flexbus_setbits);
|
||||
|
||||
void rockchip_flexbus_clrsetbits(struct rockchip_flexbus *rkfb, unsigned int reg,
|
||||
unsigned int clr_val, unsigned int set_val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
|
||||
reg_val = rockchip_flexbus_readl(rkfb, reg);
|
||||
reg_val &= ~(clr_val);
|
||||
reg_val |= set_val;
|
||||
rockchip_flexbus_writel(rkfb, reg, reg_val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_flexbus_clrsetbits);
|
||||
|
||||
#define RK3576_VCCIO_IOC_MISC_CON0 0x6400
|
||||
static void rk3576_flexbus_grf_config(struct rockchip_flexbus *rkfb, bool slave_mode, bool cpol,
|
||||
bool cpha)
|
||||
{
|
||||
u32 val = 0x3 << (16 + 7);
|
||||
|
||||
if (slave_mode) {
|
||||
val |= BIT(8);
|
||||
if ((!cpol && cpha) || (cpol && !cpha))
|
||||
val |= BIT(7);
|
||||
}
|
||||
regmap_write(rkfb->regmap_grf, RK3576_VCCIO_IOC_MISC_CON0, val);
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_flexbus_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_flexbus *rkfb = dev_id;
|
||||
u32 isr;
|
||||
|
||||
isr = rockchip_flexbus_readl(rkfb, FLEXBUS_ISR);
|
||||
|
||||
if (rkfb->opmode0 != ROCKCHIP_FLEXBUS0_OPMODE_NULL && rkfb->fb0_isr)
|
||||
rkfb->fb0_isr(rkfb, isr);
|
||||
if (rkfb->opmode1 != ROCKCHIP_FLEXBUS1_OPMODE_NULL && rkfb->fb1_isr)
|
||||
rkfb->fb1_isr(rkfb, isr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rockchip_flexbus_clk_bulk_disable(void *data)
|
||||
{
|
||||
struct rockchip_flexbus *rkfb = data;
|
||||
|
||||
clk_bulk_disable_unprepare(rkfb->num_clks, rkfb->clks);
|
||||
}
|
||||
|
||||
static int rockchip_flexbus_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_flexbus *rkfb;
|
||||
int ret;
|
||||
|
||||
rkfb = devm_kzalloc(&pdev->dev, sizeof(*rkfb), GFP_KERNEL);
|
||||
if (!rkfb)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, rkfb);
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "rockchip,flexbus0-opmode", &rkfb->opmode0);
|
||||
if (ret)
|
||||
rkfb->opmode0 = ROCKCHIP_FLEXBUS0_OPMODE_NULL;
|
||||
if (rkfb->opmode0 < ROCKCHIP_FLEXBUS0_OPMODE_NULL ||
|
||||
rkfb->opmode0 > ROCKCHIP_FLEXBUS0_OPMODE_SPI)
|
||||
return -EINVAL;
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "rockchip,flexbus1-opmode", &rkfb->opmode1);
|
||||
if (ret)
|
||||
rkfb->opmode1 = ROCKCHIP_FLEXBUS1_OPMODE_NULL;
|
||||
if (rkfb->opmode1 < ROCKCHIP_FLEXBUS1_OPMODE_NULL ||
|
||||
rkfb->opmode1 > ROCKCHIP_FLEXBUS1_OPMODE_CIF)
|
||||
return -EINVAL;
|
||||
|
||||
rkfb->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(rkfb->base))
|
||||
return PTR_ERR(rkfb->base);
|
||||
rkfb->dev = &pdev->dev;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get irq\n");
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, ret, rockchip_flexbus_isr, 0, dev_name(&pdev->dev),
|
||||
rkfb);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request irq %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rkfb->config = device_get_match_data(&pdev->dev);
|
||||
|
||||
rkfb->regmap_grf = syscon_regmap_lookup_by_phandle_optional(pdev->dev.of_node,
|
||||
"rockchip,grf");
|
||||
if (!rkfb->regmap_grf)
|
||||
dev_warn(&pdev->dev, "failed to get rockchip,grf node.\n");
|
||||
|
||||
rkfb->num_clks = devm_clk_bulk_get_all(&pdev->dev, &rkfb->clks);
|
||||
if (rkfb->num_clks <= 0) {
|
||||
dev_err(&pdev->dev, "bus clock not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = clk_bulk_prepare_enable(rkfb->num_clks, rkfb->clks);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clocks.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, rockchip_flexbus_clk_bulk_disable, rkfb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register devm action, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rkfb->opmode0 != ROCKCHIP_FLEXBUS0_OPMODE_NULL &&
|
||||
rkfb->opmode1 != ROCKCHIP_FLEXBUS1_OPMODE_NULL)
|
||||
rockchip_flexbus_writel(rkfb, FLEXBUS_COM_CTL, FLEXBUS_TX_AND_RX);
|
||||
else if (rkfb->opmode0 != ROCKCHIP_FLEXBUS0_OPMODE_NULL)
|
||||
rockchip_flexbus_writel(rkfb, FLEXBUS_COM_CTL, FLEXBUS_TX_ONLY);
|
||||
else
|
||||
rockchip_flexbus_writel(rkfb, FLEXBUS_COM_CTL, FLEXBUS_RX_ONLY);
|
||||
|
||||
return devm_of_platform_populate(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct rockchip_flexbus_config rk3576_flexbus_config = {
|
||||
.grf_config = rk3576_flexbus_grf_config,
|
||||
.txwat_start_max = 511,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_flexbus_of_match[] = {
|
||||
{ .compatible = "rockchip,rk3576-flexbus", .data = &rk3576_flexbus_config},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_flexbus_of_match);
|
||||
|
||||
static struct platform_driver rockchip_flexbus_driver = {
|
||||
.probe = rockchip_flexbus_probe,
|
||||
.driver = {
|
||||
.name = "rockchip_flexbus",
|
||||
.of_match_table = rockchip_flexbus_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rockchip_flexbus_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Rockchip Flexbus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
136
include/linux/mfd/rockchip-flexbus.h
Normal file
136
include/linux/mfd/rockchip-flexbus.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2024 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ROCKCHIP_FLEXBUS_H__
|
||||
#define __LINUX_MFD_ROCKCHIP_FLEXBUS_H__
|
||||
|
||||
#define FLEXBUS_ENR 0x000
|
||||
#define FLEXBUS_FREE_SCLK 0x004
|
||||
#define FLEXBUS_CSN_CFG 0x008
|
||||
#define FLEXBUS_COM_CTL 0x00C
|
||||
#define FLEXBUS_REMAP 0x010
|
||||
#define FLEXBUS_STOP 0x014
|
||||
#define FLEXBUS_SLAVE_MODE 0x018
|
||||
#define FLEXBUS_DVP_POL 0x01C
|
||||
#define FLEXBUS_DVP_CROP_SIZE 0x020
|
||||
#define FLEXBUS_DVP_CROP_START 0x024
|
||||
#define FLEXBUS_DVP_ORDER 0x028
|
||||
#define FLEXBUS_TX_CTL 0x040
|
||||
#define FLEXBUS_TX_NUM 0x044
|
||||
#define FLEXBUS_TXWAT_START 0x048
|
||||
#define FLEXBUS_TXFIFO_DNUM 0x04C
|
||||
#define FLEXBUS_RX_CTL 0x080
|
||||
#define FLEXBUS_RX_NUM 0x084
|
||||
#define FLEXBUS_RXFIFO_DNUM 0x088
|
||||
#define FLEXBUS_DLL_EN 0x08C
|
||||
#define FLEXBUS_DLL_NUM 0x090
|
||||
#define FLEXBUS_RXCLK_DUMMY 0x094
|
||||
#define FLEXBUS_RXCLK_CAP_CNT 0x098
|
||||
#define FLEXBUS_DMA_RD_OUTSTD 0x100
|
||||
#define FLEXBUS_DMA_WR_OUTSTD 0x104
|
||||
#define FLEXBUS_DMA_SRC_ADDR0 0x108
|
||||
#define FLEXBUS_DMA_DST_ADDR0 0x10C
|
||||
#define FLEXBUS_DMA_SRC_ADDR1 0x110
|
||||
#define FLEXBUS_DMA_DST_ADDR1 0x114
|
||||
#define FLEXBUS_DMA_SRC_LEN0 0x118
|
||||
#define FLEXBUS_DMA_DST_LEN0 0x11C
|
||||
#define FLEXBUS_DMA_SRC_LEN1 0x120
|
||||
#define FLEXBUS_DMA_DST_LEN1 0x124
|
||||
#define FLEXBUS_DMA_WAT_INT 0x128
|
||||
#define FLEXBUS_DMA_TIMEOUT 0x12C
|
||||
#define FLEXBUS_DMA_RD_LEN 0x130
|
||||
#define FLEXBUS_STATUS 0x160
|
||||
#define FLEXBUS_IMR 0x164
|
||||
#define FLEXBUS_RISR 0x168
|
||||
#define FLEXBUS_ISR 0x16C
|
||||
#define FLEXBUS_ICR 0x170
|
||||
#define FLEXBUS_TESTCLK 0x190
|
||||
#define FLEXBUS_TESTDAT 0x194
|
||||
#define FLEXBUS_REVISION 0x1F0
|
||||
|
||||
/* Bit fields in ENR */
|
||||
#define FLEXBUS_RX_ENR (BIT(16 + 1) | BIT(1))
|
||||
#define FLEXBUS_RX_DIS BIT(16 + 1)
|
||||
#define FLEXBUS_TX_ENR (BIT(16) | BIT(0))
|
||||
#define FLEXBUS_TX_DIS BIT(16)
|
||||
|
||||
/* Bit fields in FREE_SCLK */
|
||||
#define FLEXBUS_RX_FREE_MODE (BIT(16 + 1) | BIT(1))
|
||||
#define FLEXBUS_TX_FREE_MODE (BIT(16) | BIT(0))
|
||||
|
||||
/* Bit fields in SLAVE_MODE */
|
||||
#define FLEXBUS_DVP_SEL BIT(1)
|
||||
#define FLEXBUS_CLK1_IN BIT(0)
|
||||
|
||||
/* Bit fields in TX_CTL and RX_CTL */
|
||||
#define FLEXBUS_CONTINUE_MODE BIT(4)
|
||||
#define FLEXBUS_CPOL BIT(3)
|
||||
#define FLEXBUS_CPHA BIT(2)
|
||||
#define FLEXBUS_DFS_SHIFT 0
|
||||
|
||||
/* Bit fields in RX_CTL */
|
||||
#define FLEXBUS_AUTOPAD BIT(14)
|
||||
|
||||
/* Bit fields in DMA_WAT_INT */
|
||||
#define FLEXBUS_SRC_WAT_LVL_MASK 0x3
|
||||
#define FLEXBUS_SRC_WAT_LVL_SHIFT 2
|
||||
#define FLEXBUS_DST_WAT_LVL_MASK 0x3
|
||||
#define FLEXBUS_DST_WAT_LVL_SHIFT 0
|
||||
|
||||
/* Bit fields in IMR, RISR, ISR and ICR */
|
||||
#define FLEXBUS_DMA_TIMEOUT_ISR BIT(13)
|
||||
#define FLEXBUS_DMA_ERR_ISR BIT(12)
|
||||
#define FLEXBUS_DMA_DST1_ISR BIT(11)
|
||||
#define FLEXBUS_DMA_DST0_ISR BIT(10)
|
||||
#define FLEXBUS_DMA_SRC1_ISR BIT(9)
|
||||
#define FLEXBUS_DMA_SRC0_ISR BIT(8)
|
||||
#define FLEXBUS_DVP_FRAME_START_ISR BIT(7)
|
||||
#define FLEXBUS_DVP_FRAME_AB_ISR BIT(6)
|
||||
#define FLEXBUS_RX_DONE_ISR BIT(5)
|
||||
#define FLEXBUS_RX_UDF_ISR BIT(4)
|
||||
#define FLEXBUS_RX_OVF_ISR BIT(3)
|
||||
#define FLEXBUS_TX_DONE_ISR BIT(2)
|
||||
#define FLEXBUS_TX_UDF_ISR BIT(1)
|
||||
#define FLEXBUS_TX_OVF_ISR BIT(0)
|
||||
|
||||
struct rockchip_flexbus;
|
||||
|
||||
struct rockchip_flexbus_config {
|
||||
void (*grf_config)(struct rockchip_flexbus *rkfb, bool slave_mode, bool cpol, bool cpha);
|
||||
u32 txwat_start_max;
|
||||
};
|
||||
|
||||
struct rockchip_flexbus {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct regmap *regmap_grf;
|
||||
unsigned int opmode0;
|
||||
unsigned int opmode1;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
void *fb0_data;
|
||||
void *fb1_data;
|
||||
void (*fb0_isr)(struct rockchip_flexbus *rkfb, u32 isr);
|
||||
void (*fb1_isr)(struct rockchip_flexbus *rkfb, u32 isr);
|
||||
const struct rockchip_flexbus_config *config;
|
||||
};
|
||||
|
||||
enum rockchip_flexbus_dfs {
|
||||
FLEXBUS_DFS_2BIT = 0x0,
|
||||
FLEXBUS_DFS_4BIT,
|
||||
FLEXBUS_DFS_8BIT,
|
||||
FLEXBUS_DFS_16BIT,
|
||||
};
|
||||
|
||||
unsigned int rockchip_flexbus_readl(struct rockchip_flexbus *rkfb, unsigned int reg);
|
||||
void rockchip_flexbus_writel(struct rockchip_flexbus *rkfb, unsigned int reg, unsigned int val);
|
||||
void rockchip_flexbus_clrbits(struct rockchip_flexbus *rkfb, unsigned int reg,
|
||||
unsigned int clr_val);
|
||||
void rockchip_flexbus_setbits(struct rockchip_flexbus *rkfb, unsigned int reg,
|
||||
unsigned int set_val);
|
||||
void rockchip_flexbus_clrsetbits(struct rockchip_flexbus *rkfb, unsigned int reg,
|
||||
unsigned int clr_val, unsigned int set_val);
|
||||
|
||||
#endif /* __LINUX_MFD_ROCKCHIP_FLEXBUS_H__ */
|
||||
Reference in New Issue
Block a user