mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
spicc: add enhanced features of oen, clock divider
PD#164751: spicc: add enhanced features of oen, clock divider 1. use the definite and significative name "has_oen" and "has_enhance_clk_div" to replace the unclear "is_enhance". 2. add some comment about enhance clk divider. Change-Id: I9ffe51aaf696cdb09b5e486d60b5378c6433783e Signed-off-by: Sunny Luo <sunny.luo@amlogic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ Required properties:
|
||||
- compatible: should be:
|
||||
"amlogic,meson-gx-spicc" on Amlogic GX and compatible SoCs.
|
||||
"amlogic,meson-txlx-spicc" on Amlogic TXLX and compatible SoCs
|
||||
"amlogic,meson-axg-spicc" on Amlogic AXG and compatible SoCs
|
||||
- reg: physical base address and length of the controller registers
|
||||
- interrupts: The interrupt specifier
|
||||
- clock-names: Must contain "core"
|
||||
|
||||
@@ -136,7 +136,8 @@
|
||||
|
||||
struct meson_spicc_data {
|
||||
unsigned int max_speed_hz;
|
||||
bool is_enhance;
|
||||
bool has_oen;
|
||||
bool has_enhance_clk_div;
|
||||
};
|
||||
|
||||
struct meson_spicc_device {
|
||||
@@ -164,6 +165,19 @@ struct meson_spicc_device {
|
||||
#endif /* end MESON_SPICC_TEST_ENTRY */
|
||||
};
|
||||
|
||||
static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
|
||||
{
|
||||
u32 conf;
|
||||
|
||||
if (!spicc->data->has_oen)
|
||||
return;
|
||||
|
||||
conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) |
|
||||
SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN;
|
||||
|
||||
writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0);
|
||||
}
|
||||
|
||||
static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
|
||||
{
|
||||
return !!FIELD_GET(SPICC_TF,
|
||||
@@ -437,14 +451,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
|
||||
|
||||
writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG);
|
||||
|
||||
if (spicc->data->is_enhance) {
|
||||
conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0);
|
||||
conf |= (SPICC_ENH_MOSI_OEN |
|
||||
SPICC_ENH_CLK_OEN |
|
||||
SPICC_ENH_CS_OEN);
|
||||
|
||||
writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0);
|
||||
}
|
||||
meson_spicc_oen_enable(spicc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -581,30 +588,50 @@ static struct class_attribute spicc_class_attrs[] = {
|
||||
};
|
||||
#endif /* end MESON_SPICC_TEST_ENTRY */
|
||||
|
||||
static struct clk_fixed_factor spicc_old_div0 = {
|
||||
/*
|
||||
* The Clock Mux
|
||||
* x-----------------x x------------x x------\
|
||||
* |---| 0) fixed factor |---| 1) old div |----| |
|
||||
* | x-----------------x x------------x | |
|
||||
* src ---| |5) mux|-- out
|
||||
* | x-----------------x x------------x | |
|
||||
* |---| 2) fixed factor |---| 3) new div |0---| |
|
||||
* x-----------------x x------------x x------/
|
||||
*
|
||||
* Clk path for GX series:
|
||||
* src -> 0 -> 1 -> out
|
||||
*
|
||||
* Clk path for AXG series:
|
||||
* src -> 0 -> 1 -> 5 -> out
|
||||
* src -> 2 -> 3 -> 5 -> out
|
||||
*/
|
||||
|
||||
/* algorithm for div0 + div1: rate = freq / 4 / (2 ^ N) */
|
||||
static struct clk_fixed_factor meson_spicc_div0 = {
|
||||
.mult = 1,
|
||||
.div = 4,
|
||||
};
|
||||
|
||||
static struct clk_divider spicc_old_div1 = {
|
||||
static struct clk_divider meson_spicc_div1 = {
|
||||
.reg = (void *) SPICC_CONREG,
|
||||
.shift = 16,
|
||||
.width = 3,
|
||||
.flags = CLK_DIVIDER_POWER_OF_TWO,
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor spicc_new_div0 = {
|
||||
/* algorithm for div2 + div3: rate = freq / 2 / (N + 1) */
|
||||
static struct clk_fixed_factor meson_spicc_div2 = {
|
||||
.mult = 1,
|
||||
.div = 2,
|
||||
};
|
||||
|
||||
static struct clk_divider spicc_new_div1 = {
|
||||
static struct clk_divider meson_spicc_div3 = {
|
||||
.reg = (void *) SPICC_ENH_CTL0,
|
||||
.shift = 16,
|
||||
.width = 8,
|
||||
};
|
||||
|
||||
static struct clk_mux spicc_new_sel = {
|
||||
static struct clk_mux meson_spicc_sel = {
|
||||
.reg = (void *) SPICC_ENH_CTL0,
|
||||
.mask = 0x1,
|
||||
.shift = 24,
|
||||
@@ -622,8 +649,8 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
|
||||
const char *mux_parent_names[2];
|
||||
char name[32];
|
||||
|
||||
div0 = &spicc_old_div0;
|
||||
snprintf(name, sizeof(name), "%s#_old_div0", dev_name(dev));
|
||||
div0 = &meson_spicc_div0;
|
||||
snprintf(name, sizeof(name), "%s#_div0", dev_name(dev));
|
||||
init.name = name;
|
||||
init.ops = &clk_fixed_factor_ops;
|
||||
init.flags = 0;
|
||||
@@ -637,8 +664,8 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
|
||||
if (WARN_ON(IS_ERR(clk)))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
div1 = &spicc_old_div1;
|
||||
snprintf(name, sizeof(name), "%s#_old_div1", dev_name(dev));
|
||||
div1 = &meson_spicc_div1;
|
||||
snprintf(name, sizeof(name), "%s#_div1", dev_name(dev));
|
||||
init.name = name;
|
||||
init.ops = &clk_divider_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
@@ -653,16 +680,15 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
|
||||
if (WARN_ON(IS_ERR(clk)))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
if (spicc->data->is_enhance == false) {
|
||||
if (spicc->data->has_enhance_clk_div == false) {
|
||||
spicc->clk = clk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* register new divider path */
|
||||
mux_parent_names[0] = __clk_get_name(clk);
|
||||
|
||||
div0 = &spicc_new_div0;
|
||||
snprintf(name, sizeof(name), "%s#_new_div0", dev_name(dev));
|
||||
div0 = &meson_spicc_div2;
|
||||
snprintf(name, sizeof(name), "%s#_div2", dev_name(dev));
|
||||
init.name = name;
|
||||
init.ops = &clk_fixed_factor_ops;
|
||||
init.flags = 0;
|
||||
@@ -676,8 +702,8 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
|
||||
if (WARN_ON(IS_ERR(clk)))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
div1 = &spicc_new_div1;
|
||||
snprintf(name, sizeof(name), "%s#_new_div1", dev_name(dev));
|
||||
div1 = &meson_spicc_div3;
|
||||
snprintf(name, sizeof(name), "%s#_div3", dev_name(dev));
|
||||
init.name = name;
|
||||
init.ops = &clk_divider_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
@@ -694,7 +720,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
|
||||
|
||||
mux_parent_names[1] = __clk_get_name(clk);
|
||||
|
||||
mux = &spicc_new_sel;
|
||||
mux = &meson_spicc_sel;
|
||||
snprintf(name, sizeof(name), "%s#_sel", dev_name(dev));
|
||||
init.name = name;
|
||||
init.ops = &clk_mux_ops;
|
||||
@@ -829,13 +855,19 @@ static int meson_spicc_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct meson_spicc_data meson_spicc_gx_data = {
|
||||
.max_speed_hz = 30000000,
|
||||
.is_enhance = false,
|
||||
.max_speed_hz = 30000000,
|
||||
};
|
||||
|
||||
static const struct meson_spicc_data meson_spicc_txlx_data = {
|
||||
.max_speed_hz = 80000000,
|
||||
.is_enhance = true,
|
||||
.max_speed_hz = 80000000,
|
||||
.has_oen = true,
|
||||
.has_enhance_clk_div = true,
|
||||
};
|
||||
|
||||
static const struct meson_spicc_data meson_spicc_axg_data = {
|
||||
.max_speed_hz = 80000000,
|
||||
.has_oen = true,
|
||||
.has_enhance_clk_div = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_spicc_of_match[] = {
|
||||
@@ -847,6 +879,10 @@ static const struct of_device_id meson_spicc_of_match[] = {
|
||||
.compatible = "amlogic,meson-txlx-spicc",
|
||||
.data = &meson_spicc_txlx_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-axg-spicc",
|
||||
.data = &meson_spicc_axg_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_spicc_of_match);
|
||||
|
||||
Reference in New Issue
Block a user