summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c6
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c140
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h2
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7724.h1
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7723.c76
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7724.c44
-rw-r--r--drivers/sh/clk/core.c9
-rw-r--r--drivers/sh/clk/cpg.c77
-rw-r--r--drivers/sh/pfc.c137
-rw-r--r--drivers/tty/serial/sh-sci.c183
-rw-r--r--include/linux/serial_sci.h22
-rw-r--r--include/linux/sh_clk.h10
-rw-r--r--include/linux/sh_pfc.h11
13 files changed, 545 insertions, 173 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 995a9c3..e349c22 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -411,11 +411,11 @@ static struct clk *fsibckcr_parent[] = {
};
static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
- [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0,
+ [DIV6_HDMI] = SH_CLK_DIV6_EXT(HDMICKCR, 0,
hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
- [DIV6_FSIA] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIACKCR, 0,
+ [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
fsiackcr_parent, ARRAY_SIZE(fsiackcr_parent), 6, 2),
- [DIV6_FSIB] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIBCKCR, 0,
+ [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
};
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 1370a89..34944d0 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -92,6 +92,24 @@ static struct clk_ops div2_clk_ops = {
.recalc = div2_recalc,
};
+static unsigned long div7_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 7;
+}
+
+static struct clk_ops div7_clk_ops = {
+ .recalc = div7_recalc,
+};
+
+static unsigned long div13_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 13;
+}
+
+static struct clk_ops div13_clk_ops = {
+ .recalc = div13_recalc,
+};
+
/* Divide extal1 by two */
static struct clk extal1_div2_clk = {
.ops = &div2_clk_ops,
@@ -174,12 +192,29 @@ static struct clk pll3_clk = {
.enable_bit = 3,
};
-/* Divide PLL1 by two */
+/* Divide PLL */
static struct clk pll1_div2_clk = {
.ops = &div2_clk_ops,
.parent = &pll1_clk,
};
+static struct clk pll1_div7_clk = {
+ .ops = &div7_clk_ops,
+ .parent = &pll1_clk,
+};
+
+static struct clk pll1_div13_clk = {
+ .ops = &div13_clk_ops,
+ .parent = &pll1_clk,
+};
+
+/* External input clock */
+struct clk sh73a0_extcki_clk = {
+};
+
+struct clk sh73a0_extalr_clk = {
+};
+
static struct clk *main_clks[] = {
&r_clk,
&sh73a0_extal1_clk,
@@ -193,6 +228,10 @@ static struct clk *main_clks[] = {
&pll2_clk,
&pll3_clk,
&pll1_div2_clk,
+ &pll1_div7_clk,
+ &pll1_div13_clk,
+ &sh73a0_extcki_clk,
+ &sh73a0_extalr_clk,
};
static void div4_kick(struct clk *clk)
@@ -246,27 +285,84 @@ enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
DIV6_NR };
+static struct clk *vck_parent[8] = {
+ [0] = &pll1_div2_clk,
+ [1] = &pll2_clk,
+ [2] = &sh73a0_extcki_clk,
+ [3] = &sh73a0_extal2_clk,
+ [4] = &main_div2_clk,
+ [5] = &sh73a0_extalr_clk,
+ [6] = &main_clk,
+};
+
+static struct clk *pll_parent[4] = {
+ [0] = &pll1_div2_clk,
+ [1] = &pll2_clk,
+ [2] = &pll1_div13_clk,
+};
+
+static struct clk *hsi_parent[4] = {
+ [0] = &pll1_div2_clk,
+ [1] = &pll2_clk,
+ [2] = &pll1_div7_clk,
+};
+
+static struct clk *pll_extal2_parent[] = {
+ [0] = &pll1_div2_clk,
+ [1] = &pll2_clk,
+ [2] = &sh73a0_extal2_clk,
+ [3] = &sh73a0_extal2_clk,
+};
+
+static struct clk *dsi_parent[8] = {
+ [0] = &pll1_div2_clk,
+ [1] = &pll2_clk,
+ [2] = &main_clk,
+ [3] = &sh73a0_extal2_clk,
+ [4] = &sh73a0_extcki_clk,
+};
+
static struct clk div6_clks[DIV6_NR] = {
- [DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0),
- [DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0),
- [DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0),
- [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT),
- [DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0),
- [DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0),
- [DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),
- [DIV6_SDHI2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0),
- [DIV6_FSIA] = SH_CLK_DIV6(&pll1_div2_clk, FSIACKCR, 0),
- [DIV6_FSIB] = SH_CLK_DIV6(&pll1_div2_clk, FSIBCKCR, 0),
- [DIV6_SUB] = SH_CLK_DIV6(&sh73a0_extal2_clk, SUBCKCR, 0),
- [DIV6_SPUA] = SH_CLK_DIV6(&pll1_div2_clk, SPUACKCR, 0),
- [DIV6_SPUV] = SH_CLK_DIV6(&pll1_div2_clk, SPUVCKCR, 0),
- [DIV6_MSU] = SH_CLK_DIV6(&pll1_div2_clk, MSUCKCR, 0),
- [DIV6_HSI] = SH_CLK_DIV6(&pll1_div2_clk, HSICKCR, 0),
- [DIV6_MFG1] = SH_CLK_DIV6(&pll1_div2_clk, MFCK1CR, 0),
- [DIV6_MFG2] = SH_CLK_DIV6(&pll1_div2_clk, MFCK2CR, 0),
- [DIV6_DSIT] = SH_CLK_DIV6(&pll1_div2_clk, DSITCKCR, 0),
- [DIV6_DSI0P] = SH_CLK_DIV6(&pll1_div2_clk, DSI0PCKCR, 0),
- [DIV6_DSI1P] = SH_CLK_DIV6(&pll1_div2_clk, DSI1PCKCR, 0),
+ [DIV6_VCK1] = SH_CLK_DIV6_EXT(VCLKCR1, 0,
+ vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+ [DIV6_VCK2] = SH_CLK_DIV6_EXT(VCLKCR2, 0,
+ vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+ [DIV6_VCK3] = SH_CLK_DIV6_EXT(VCLKCR3, 0,
+ vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+ [DIV6_ZB1] = SH_CLK_DIV6_EXT(ZBCKCR, CLK_ENABLE_ON_INIT,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_FLCTL] = SH_CLK_DIV6_EXT(FLCKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_SDHI0] = SH_CLK_DIV6_EXT(SD0CKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+ [DIV6_SDHI1] = SH_CLK_DIV6_EXT(SD1CKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+ [DIV6_SDHI2] = SH_CLK_DIV6_EXT(SD2CKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+ [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 6, 1),
+ [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 6, 1),
+ [DIV6_SUB] = SH_CLK_DIV6_EXT(SUBCKCR, 0,
+ pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+ [DIV6_SPUA] = SH_CLK_DIV6_EXT(SPUACKCR, 0,
+ pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+ [DIV6_SPUV] = SH_CLK_DIV6_EXT(SPUVCKCR, 0,
+ pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+ [DIV6_MSU] = SH_CLK_DIV6_EXT(MSUCKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_HSI] = SH_CLK_DIV6_EXT(HSICKCR, 0,
+ hsi_parent, ARRAY_SIZE(hsi_parent), 6, 2),
+ [DIV6_MFG1] = SH_CLK_DIV6_EXT(MFCK1CR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_MFG2] = SH_CLK_DIV6_EXT(MFCK2CR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_DSIT] = SH_CLK_DIV6_EXT(DSITCKCR, 0,
+ pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+ [DIV6_DSI0P] = SH_CLK_DIV6_EXT(DSI0PCKCR, 0,
+ dsi_parent, ARRAY_SIZE(dsi_parent), 12, 3),
+ [DIV6_DSI1P] = SH_CLK_DIV6_EXT(DSI1PCKCR, 0,
+ dsi_parent, ARRAY_SIZE(dsi_parent), 12, 3),
};
enum { MSTP001,
@@ -403,7 +499,7 @@ void __init sh73a0_clock_init(void)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
- ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+ ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index be78a2c..13a18d3 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -46,6 +46,8 @@ extern void sh73a0_clock_init(void);
extern void sh73a0_pinmux_init(void);
extern struct clk sh73a0_extal1_clk;
extern struct clk sh73a0_extal2_clk;
+extern struct clk sh73a0_extcki_clk;
+extern struct clk sh73a0_extalr_clk;
extern unsigned int sh73a0_get_core_count(void);
extern void sh73a0_secondary_init(unsigned int cpu);
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7724.h b/arch/sh/include/cpu-sh4/cpu/sh7724.h
index cbc47e6..36ce466 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7724.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7724.h
@@ -314,5 +314,6 @@ enum {
extern struct clk sh7724_fsimcka_clk;
extern struct clk sh7724_fsimckb_clk;
+extern struct clk sh7724_dv_clki;
#endif /* __ASM_SH7724_H__ */
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
index 3cc3827..f254166 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
@@ -233,73 +233,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
- {
- /* TMU0 */
- .dev_id = "sh_tmu.0",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU0],
- }, {
- /* TMU1 */
- .dev_id = "sh_tmu.1",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU0],
- }, {
- /* TMU2 */
- .dev_id = "sh_tmu.2",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU0],
- },
CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
- {
- /* TMU3 */
- .dev_id = "sh_tmu.3",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU1],
- }, {
- /* TMU4 */
- .dev_id = "sh_tmu.4",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU1],
- }, {
- /* TMU5 */
- .dev_id = "sh_tmu.5",
- .con_id = "tmu_fck",
- .clk = &mstp_clks[HWBLK_TMU1],
- },
CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
- {
- /* SCIF0 */
- .dev_id = "sh-sci.0",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF0],
- }, {
- /* SCIF1 */
- .dev_id = "sh-sci.1",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF1],
- }, {
- /* SCIF2 */
- .dev_id = "sh-sci.2",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF2],
- }, {
- /* SCIF3 */
- .dev_id = "sh-sci.3",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF3],
- }, {
- /* SCIF4 */
- .dev_id = "sh-sci.4",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF4],
- }, {
- /* SCIF5 */
- .dev_id = "sh-sci.5",
- .con_id = "sci_fck",
- .clk = &mstp_clks[HWBLK_SCIF5],
- },
CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
CLKDEV_CON_ID("meram0", &mstp_clks[HWBLK_MERAM]),
@@ -324,6 +261,19 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU2H0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU0]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU0]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU0]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
};
int __init arch_clk_init(void)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index 8668f55..9ee4b36 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -111,13 +111,16 @@ static struct clk div3_clk = {
.parent = &pll_clk,
};
-/* External input clock (pin name: FSIMCKA/FSIMCKB ) */
+/* External input clock (pin name: FSIMCKA/FSIMCKB/DV_CLKI ) */
struct clk sh7724_fsimcka_clk = {
};
struct clk sh7724_fsimckb_clk = {
};
+struct clk sh7724_dv_clki = {
+};
+
static struct clk *main_clks[] = {
&r_clk,
&extal_clk,
@@ -126,6 +129,7 @@ static struct clk *main_clks[] = {
&div3_clk,
&sh7724_fsimcka_clk,
&sh7724_fsimckb_clk,
+ &sh7724_dv_clki,
};
static void div4_kick(struct clk *clk)
@@ -163,17 +167,20 @@ struct clk div4_clks[DIV4_NR] = {
[DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),
};
-enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR };
+enum { DIV6_V, DIV6_I, DIV6_S, DIV6_FA, DIV6_FB, DIV6_NR };
-static struct clk div6_clks[DIV6_NR] = {
- [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
- [DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0),
- [DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
+/* Indices are important - they are the actual src selecting values */
+static struct clk *common_parent[] = {
+ [0] = &div3_clk,
+ [1] = NULL,
};
-enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR };
+static struct clk *vclkcr_parent[8] = {
+ [0] = &div3_clk,
+ [2] = &sh7724_dv_clki,
+ [4] = &extal_clk,
+};
-/* Indices are important - they are the actual src selecting values */
static struct clk *fclkacr_parent[] = {
[0] = &div3_clk,
[1] = NULL,
@@ -188,10 +195,16 @@ static struct clk *fclkbcr_parent[] = {
[3] = NULL,
};
-static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
- [DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0,
+static struct clk div6_clks[DIV6_NR] = {
+ [DIV6_V] = SH_CLK_DIV6_EXT(VCLKCR, 0,
+ vclkcr_parent, ARRAY_SIZE(vclkcr_parent), 12, 3),
+ [DIV6_I] = SH_CLK_DIV6_EXT(IRDACLKCR, 0,
+ common_parent, ARRAY_SIZE(common_parent), 6, 1),
+ [DIV6_S] = SH_CLK_DIV6_EXT(SPUCLKCR, CLK_ENABLE_ON_INIT,
+ common_parent, ARRAY_SIZE(common_parent), 6, 1),
+ [DIV6_FA] = SH_CLK_DIV6_EXT(FCLKACR, 0,
fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),
- [DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0,
+ [DIV6_FB] = SH_CLK_DIV6_EXT(FCLKBCR, 0,
fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
};
@@ -269,8 +282,8 @@ static struct clk_lookup lookups[] = {
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
- CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]),
- CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]),
+ CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]),
+ CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]),
CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),
CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),
@@ -356,10 +369,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
- ret = sh_clk_div6_register(div6_clks, DIV6_NR);
-
- if (!ret)
- ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
+ ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index db257a3..7715de2 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -355,7 +355,7 @@ static int clk_establish_mapping(struct clk *clk)
*/
if (!clk->parent) {
clk->mapping = &dummy_mapping;
- return 0;
+ goto out;
}
/*
@@ -384,6 +384,9 @@ static int clk_establish_mapping(struct clk *clk)
}
clk->mapping = mapping;
+out:
+ clk->mapped_reg = clk->mapping->base;
+ clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys;
return 0;
}
@@ -402,10 +405,12 @@ static void clk_teardown_mapping(struct clk *clk)
/* Nothing to do */
if (mapping == &dummy_mapping)
- return;
+ goto out;
kref_put(&mapping->ref, clk_destroy_mapping);
clk->mapping = NULL;
+out:
+ clk->mapped_reg = NULL;
}
int clk_register(struct clk *clk)
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 82dd6fb..a0d8faa 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -15,15 +15,15 @@
static int sh_clk_mstp32_enable(struct clk *clk)
{
- __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
- clk->enable_reg);
+ iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
+ clk->mapped_reg);
return 0;
}
static void sh_clk_mstp32_disable(struct clk *clk)
{
- __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
- clk->enable_reg);
+ iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
+ clk->mapped_reg);
}
static struct clk_ops sh_clk_mstp32_clk_ops = {
@@ -72,7 +72,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, NULL);
- idx = __raw_readl(clk->enable_reg) & 0x003f;
+ idx = ioread32(clk->mapped_reg) & 0x003f;
return clk->freq_table[idx].frequency;
}
@@ -98,10 +98,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
if (ret < 0)
return ret;
- value = __raw_readl(clk->enable_reg) &
+ value = ioread32(clk->mapped_reg) &
~(((1 << clk->src_width) - 1) << clk->src_shift);
- __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
+ iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
/* Rebuild the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +119,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = __raw_readl(clk->enable_reg);
+ value = ioread32(clk->mapped_reg);
value &= ~0x3f;
value |= idx;
- __raw_writel(value, clk->enable_reg);
+ iowrite32(value, clk->mapped_reg);
return 0;
}
@@ -133,9 +133,9 @@ static int sh_clk_div6_enable(struct clk *clk)
ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
- value = __raw_readl(clk->enable_reg);
+ value = ioread32(clk->mapped_reg);
value &= ~0x100; /* clear stop bit to enable clock */
- __raw_writel(value, clk->enable_reg);
+ iowrite32(value, clk->mapped_reg);
}
return ret;
}
@@ -144,10 +144,10 @@ static void sh_clk_div6_disable(struct clk *clk)
{
unsigned long value;
- value = __raw_readl(clk->enable_reg);
+ value = ioread32(clk->mapped_reg);
value |= 0x100; /* stop clock */
value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
- __raw_writel(value, clk->enable_reg);
+ iowrite32(value, clk->mapped_reg);
}
static struct clk_ops sh_clk_div6_clk_ops = {
@@ -167,6 +167,38 @@ static struct clk_ops sh_clk_div6_reparent_clk_ops = {
.set_parent = sh_clk_div6_set_parent,
};
+static int __init sh_clk_init_parent(struct clk *clk)
+{
+ u32 val;
+
+ if (clk->parent)
+ return 0;
+
+ if (!clk->parent_table || !clk->parent_num)
+ return 0;
+
+ if (!clk->src_width) {
+ pr_err("sh_clk_init_parent: cannot select parent clock\n");
+ return -EINVAL;
+ }
+
+ val = (ioread32(clk->mapped_reg) >> clk->src_shift);
+ val &= (1 << clk->src_width) - 1;
+
+ if (val >= clk->parent_num) {
+ pr_err("sh_clk_init_parent: parent table size failed\n");
+ return -EINVAL;
+ }
+
+ clk->parent = clk->parent_table[val];
+ if (!clk->parent) {
+ pr_err("sh_clk_init_parent: unable to set parent");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
struct clk_ops *ops)
{
@@ -190,6 +222,9 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
clkp->ops = ops;
clkp->freq_table = freq_table + (k * freq_table_size);
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+ ret = sh_clk_init_parent(clkp);
+ if (ret < 0)
+ break;
ret = clk_register(clkp);
}
@@ -217,7 +252,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, &clk->arch_flags);
- idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
+ idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
return clk->freq_table[idx].frequency;
}
@@ -235,15 +270,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
*/
if (parent->flags & CLK_ENABLE_ON_INIT)
- value = __raw_readl(clk->enable_reg) & ~(1 << 7);
+ value = ioread32(clk->mapped_reg) & ~(1 << 7);
else
- value = __raw_readl(clk->enable_reg) | (1 << 7);
+ value = ioread32(clk->mapped_reg) | (1 << 7);
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
- __raw_writel(value, clk->enable_reg);
+ iowrite32(value, clk->mapped_reg);
/* Rebiuld the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -260,10 +295,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = __raw_readl(clk->enable_reg);
+ value = ioread32(clk->mapped_reg);
value &= ~(0xf << clk->enable_bit);
value |= (idx << clk->enable_bit);
- __raw_writel(value, clk->enable_reg);
+ iowrite32(value, clk->mapped_reg);
if (d4t->kick)
d4t->kick(clk);
@@ -273,13 +308,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
static int sh_clk_div4_enable(struct clk *clk)
{
- __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
+ iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
return 0;
}
static void sh_clk_div4_disable(struct clk *clk)
{
- __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
+ iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
}
static struct clk_ops sh_clk_div4_clk_ops = {
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c
index e67fe17..e7d127a 100644
--- a/drivers/sh/pfc.c
+++ b/drivers/sh/pfc.c
@@ -19,6 +19,75 @@
#include <linux/irq.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+
+static void pfc_iounmap(struct pinmux_info *pip)
+{
+ int k;
+
+ for (k = 0; k < pip->num_resources; k++)
+ if (pip->window[k].virt)
+ iounmap(pip->window[k].virt);
+
+ kfree(pip->window);
+ pip->window = NULL;
+}
+
+static int pfc_ioremap(struct pinmux_info *pip)
+{
+ struct resource *res;
+ int k;
+
+ if (!pip->num_resources)
+ return 0;
+
+ pip->window = kzalloc(pip->num_resources * sizeof(*pip->window),
+ GFP_NOWAIT);
+ if (!pip->window)
+ goto err1;
+
+ for (k = 0; k < pip->num_resources; k++) {
+ res = pip->resource + k;
+ WARN_ON(resource_type(res) != IORESOURCE_MEM);
+ pip->window[k].phys = res->start;
+ pip->window[k].size = resource_size(res);
+ pip->window[k].virt = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!pip->window[k].virt)
+ goto err2;
+ }
+
+ return 0;
+
+err2:
+ pfc_iounmap(pip);
+err1:
+ return -1;
+}
+
+static void __iomem *pfc_phys_to_virt(struct pinmux_info *pip,
+ unsigned long address)
+{
+ struct pfc_window *window;
+ int k;
+
+ /* scan through physical windows and convert address */
+ for (k = 0; k < pip->num_resources; k++) {
+ window = pip->window + k;
+
+ if (address < window->phys)
+ continue;
+
+ if (address >= (window->phys + window->size))
+ continue;
+
+ return window->virt + (address - window->phys);
+ }
+
+ /* no windows defined, register must be 1:1 mapped virt:phys */
+ return (void __iomem *)address;
+}
static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
{
@@ -31,35 +100,35 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
return 1;
}
-static unsigned long gpio_read_raw_reg(unsigned long reg,
+static unsigned long gpio_read_raw_reg(void __iomem *mapped_reg,
unsigned long reg_width)
{
switch (reg_width) {
case 8:
- return __raw_readb(reg);
+ return ioread8(mapped_reg);
case 16:
- return __raw_readw(reg);
+ return ioread16(mapped_reg);
case 32:
- return __raw_readl(reg);
+ return ioread32(mapped_reg);
}
BUG();
return 0;
}
-static void gpio_write_raw_reg(unsigned long reg,
+static void gpio_write_raw_reg(void __iomem *mapped_reg,
unsigned long reg_width,
unsigned long data)
{
switch (reg_width) {
case 8:
- __raw_writeb(data, reg);
+ iowrite8(data, mapped_reg);
return;
case 16:
- __raw_writew(data, reg);
+ iowrite16(data, mapped_reg);
return;
case 32:
- __raw_writel(data, reg);
+ iowrite32(data, mapped_reg);
return;
}
@@ -82,11 +151,12 @@ static void gpio_write_bit(struct pinmux_data_reg *dr,
else
clear_bit(pos, &dr->reg_shadow);
- gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
+ gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
}
-static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
- unsigned long field_width, unsigned long in_pos)
+static int gpio_read_reg(void __iomem *mapped_reg, unsigned long reg_width,
+ unsigned long field_width, unsigned long in_pos,
+ unsigned long reg)
{
unsigned long data, mask, pos;
@@ -98,13 +168,13 @@ static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
"r_width = %ld, f_width = %ld\n",
reg, pos, reg_width, field_width);
- data = gpio_read_raw_reg(reg, reg_width);
+ data = gpio_read_raw_reg(mapped_reg, reg_width);
return (data >> pos) & mask;
}
-static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
+static void gpio_write_reg(void __iomem *mapped_reg, unsigned long reg_width,
unsigned long field_width, unsigned long in_pos,
- unsigned long value)
+ unsigned long value, unsigned long reg)
{
unsigned long mask, pos;
@@ -120,13 +190,13 @@ static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
switch (reg_width) {
case 8:
- __raw_writeb((__raw_readb(reg) & mask) | value, reg);
+ iowrite8((ioread8(mapped_reg) & mask) | value, mapped_reg);
break;
case 16:
- __raw_writew((__raw_readw(reg) & mask) | value, reg);
+ iowrite16((ioread16(mapped_reg) & mask) | value, mapped_reg);
break;
case 32:
- __raw_writel((__raw_readl(reg) & mask) | value, reg);
+ iowrite32((ioread32(mapped_reg) & mask) | value, mapped_reg);
break;
}
}
@@ -147,6 +217,8 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
if (!data_reg->reg_width)
break;
+ data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
+
for (n = 0; n < data_reg->reg_width; n++) {
if (data_reg->enum_ids[n] == gpiop->enum_id) {
gpiop->flags &= ~PINMUX_FLAG_DREG;
@@ -179,7 +251,8 @@ static void setup_data_regs(struct pinmux_info *gpioc)
if (!drp->reg_width)
break;
- drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
+ drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
+ drp->reg_width);
k++;
}
}
@@ -266,12 +339,16 @@ static void write_config_reg(struct pinmux_info *gpioc,
int index)
{
unsigned long ncomb, pos, value;
+ void __iomem *mapped_reg;
ncomb = 1 << crp->field_width;
pos = index / ncomb;
value = index % ncomb;
- gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
+ mapped_reg = pfc_phys_to_virt(gpioc, crp->reg);
+
+ gpio_write_reg(mapped_reg, crp->reg_width, crp->field_width,
+ pos, value, crp->reg);
}
static int check_config_reg(struct pinmux_info *gpioc,
@@ -279,13 +356,16 @@ static int check_config_reg(struct pinmux_info *gpioc,
int index)
{
unsigned long ncomb, pos, value;
+ void __iomem *mapped_reg;
ncomb = 1 << crp->field_width;
pos = index / ncomb;
value = index % ncomb;
- if (gpio_read_reg(crp->reg, crp->reg_width,
- crp->field_width, pos) == value)
+ mapped_reg = pfc_phys_to_virt(gpioc, crp->reg);
+
+ if (gpio_read_reg(mapped_reg, crp->reg_width,
+ crp->field_width, pos, crp->reg) == value)
return 0;
return -1;
@@ -564,7 +644,7 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
return -EINVAL;
- return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
+ return gpio_read_reg(dr->mapped_reg, dr->reg_width, 1, bit, dr->reg);
}
static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -606,10 +686,15 @@ static int sh_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
int register_pinmux(struct pinmux_info *pip)
{
struct gpio_chip *chip = &pip->chip;
+ int ret;
pr_info("%s handling gpio %d -> %d\n",
pip->name, pip->first_gpio, pip->last_gpio);
+ ret = pfc_ioremap(pip);
+ if (ret < 0)
+ return ret;
+
setup_data_regs(pip);
chip->request = sh_gpio_request;
@@ -627,12 +712,16 @@ int register_pinmux(struct pinmux_info *pip)
chip->base = pip->first_gpio;
chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
- return gpiochip_add(chip);
+ ret = gpiochip_add(chip);
+ if (ret < 0)
+ pfc_iounmap(pip);
+
+ return ret;
}
int unregister_pinmux(struct pinmux_info *pip)
{
pr_info("%s deregistering\n", pip->name);
-
+ pfc_iounmap(pip);
return gpiochip_remove(&pip->chip);
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index aff9d61..9e62349 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -50,6 +50,7 @@
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#ifdef CONFIG_SUPERH
#include <asm/sh_bios.h>
@@ -73,6 +74,7 @@ struct sci_port {
struct clk *fclk;
char *irqstr[SCIx_NR_IRQS];
+ char *gpiostr[SCIx_NR_FNS];
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
@@ -474,8 +476,15 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
if (!reg->size)
return;
- if (!(cflag & CRTSCTS))
- sci_out(port, SCSPTR, 0x0080); /* Set RTS = 1 */
+ if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) &&
+ ((!(cflag & CRTSCTS)))) {
+ unsigned short status;
+
+ status = sci_in(port, SCSPTR);
+ status &= ~SCSPTR_CTSIO;
+ status |= SCSPTR_RTSIO;
+ sci_out(port, SCSPTR, status); /* Set RTS = 1 */
+ }
}
static int sci_txfill(struct uart_port *port)
@@ -621,6 +630,7 @@ static void sci_receive_chars(struct uart_port *port)
} else {
for (i = 0; i < count; i++) {
char c = sci_in(port, SCxRDR);
+
status = sci_in(port, SCxSR);
#if defined(CONFIG_CPU_SH3)
/* Skip "chars" during break */
@@ -649,9 +659,11 @@ static void sci_receive_chars(struct uart_port *port)
/* Store data and status */
if (status & SCxSR_FER(port)) {
flag = TTY_FRAME;
+ port->icount.frame++;
dev_notice(port->dev, "frame error\n");
} else if (status & SCxSR_PER(port)) {
flag = TTY_PARITY;
+ port->icount.parity++;
dev_notice(port->dev, "parity error\n");
} else
flag = TTY_NORMAL;
@@ -723,6 +735,8 @@ static int sci_handle_errors(struct uart_port *port)
*/
if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) {
if (status & (1 << s->cfg->overrun_bit)) {
+ port->icount.overrun++;
+
/* overrun error */
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
copied++;
@@ -737,6 +751,8 @@ static int sci_handle_errors(struct uart_port *port)
struct sci_port *sci_port = to_sci_port(port);
if (!sci_port->break_flag) {
+ port->icount.brk++;
+
sci_port->break_flag = 1;
sci_schedule_break_timer(sci_port);
@@ -752,6 +768,8 @@ static int sci_handle_errors(struct uart_port *port)
} else {
/* frame error */
+ port->icount.frame++;
+
if (tty_insert_flip_char(tty, 0, TTY_FRAME))
copied++;
@@ -761,6 +779,8 @@ static int sci_handle_errors(struct uart_port *port)
if (status & SCxSR_PER(port)) {
/* parity error */
+ port->icount.parity++;
+
if (tty_insert_flip_char(tty, 0, TTY_PARITY))
copied++;
@@ -787,6 +807,8 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
if ((sci_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) {
sci_out(port, SCLSR, 0);
+ port->icount.overrun++;
+
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
tty_flip_buffer_push(tty);
@@ -812,6 +834,9 @@ static int sci_handle_breaks(struct uart_port *port)
/* Debounce break */
s->break_flag = 1;
#endif
+
+ port->icount.brk++;
+
/* Notify of BREAK */
if (tty_insert_flip_char(tty, 0, TTY_BREAK))
copied++;
@@ -1082,6 +1107,67 @@ static void sci_free_irq(struct sci_port *port)
}
}
+static const char *sci_gpio_names[SCIx_NR_FNS] = {
+ "sck", "rxd", "txd", "cts", "rts",
+};
+
+static const char *sci_gpio_str(unsigned int index)
+{
+ return sci_gpio_names[index];
+}
+
+static void __devinit sci_init_gpios(struct sci_port *port)
+{
+ struct uart_port *up = &port->port;
+ int i;
+
+ if (!port->cfg)
+ return;
+
+ for (i = 0; i < SCIx_NR_FNS; i++) {
+ const char *desc;
+ int ret;
+
+ if (!port->cfg->gpios[i])
+ continue;
+
+ desc = sci_gpio_str(i);
+
+ port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s",
+ dev_name(up->dev), desc);
+
+ /*
+ * If we've failed the allocation, we can still continue
+ * on with a NULL string.
+ */
+ if (!port->gpiostr[i])
+ dev_notice(up->dev, "%s string allocation failure\n",
+ desc);
+
+ ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]);
+ if (unlikely(ret != 0)) {
+ dev_notice(up->dev, "failed %s gpio request\n", desc);
+
+ /*
+ * If we can't get the GPIO for whatever reason,
+ * no point in keeping the verbose string around.
+ */
+ kfree(port->gpiostr[i]);
+ }
+ }
+}
+
+static void sci_free_gpios(struct sci_port *port)
+{
+ int i;
+
+ for (i = 0; i < SCIx_NR_FNS; i++)
+ if (port->cfg->gpios[i]) {
+ gpio_free(port->cfg->gpios[i]);
+ kfree(port->gpiostr[i]);
+ }
+}
+
static unsigned int sci_tx_empty(struct uart_port *port)
{
unsigned short status = sci_in(port, SCxSR);
@@ -1090,19 +1176,39 @@ static unsigned int sci_tx_empty(struct uart_port *port)
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
}
+/*
+ * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
+ * CTS/RTS is supported in hardware by at least one port and controlled
+ * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
+ * handled via the ->init_pins() op, which is a bit of a one-way street,
+ * lacking any ability to defer pin control -- this will later be
+ * converted over to the GPIO framework).
+ *
+ * Other modes (such as loopback) are supported generically on certain
+ * port types, but not others. For these it's sufficient to test for the
+ * existence of the support register and simply ignore the port type.
+ */
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
- /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
- /* If you have signals for DTR and DCD, please implement here. */
+ if (mctrl & TIOCM_LOOP) {
+ struct plat_sci_reg *reg;
+
+ /*
+ * Standard loopback mode for SCFCR ports.
+ */
+ reg = sci_getreg(port, SCFCR);
+ if (reg->size)
+ sci_out(port, SCFCR, sci_in(port, SCFCR) | 1);
+ }
}
static unsigned int sci_get_mctrl(struct uart_port *port)
{
- /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
- and CTS/RTS */
-
- return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
+ /*
+ * CTS/RTS is handled in hardware when supported, while nothing
+ * else is wired up. Keep it simple and simply assert DSR/CAR.
+ */
+ return TIOCM_DSR | TIOCM_CAR;
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1449,12 +1555,17 @@ static void sci_stop_rx(struct uart_port *port)
static void sci_enable_ms(struct uart_port *port)
{
- /* Nothing here yet .. */
+ /*
+ * Not supported by hardware, always a nop.
+ */
}
static void sci_break_ctl(struct uart_port *port, int break_state)
{
- /* Nothing here yet .. */
+ /*
+ * Not supported by hardware. Most parts couple break and rx
+ * interrupts together, with break detection always enabled.
+ */
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1652,6 +1763,7 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
static void sci_reset(struct uart_port *port)
{
+ struct plat_sci_reg *reg;
unsigned int status;
do {
@@ -1660,7 +1772,8 @@ static void sci_reset(struct uart_port *port)
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
- if (port->type != PORT_SCI)
+ reg = sci_getreg(port, SCFCR);
+ if (reg->size)
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
}
@@ -1668,9 +1781,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct sci_port *s = to_sci_port(port);
+ struct plat_sci_reg *reg;
unsigned int baud, smr_val, max_baud;
int t = -1;
- u16 scfcr = 0;
/*
* earlyprintk comes here early on with port->uartclk set to zero.
@@ -1720,7 +1833,27 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
}
sci_init_pins(port, termios->c_cflag);
- sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
+
+ reg = sci_getreg(port, SCFCR);
+ if (reg->size) {
+ unsigned short ctrl = sci_in(port, SCFCR);
+
+ if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) {
+ if (termios->c_cflag & CRTSCTS)
+ ctrl |= SCFCR_MCE;
+ else
+ ctrl &= ~SCFCR_MCE;
+ }
+
+ /*
+ * As we've done a sci_reset() above, ensure we don't
+ * interfere with the FIFOs while toggling MCE. As the
+ * reset values could still be set, simply mask them out.
+ */
+ ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
+
+ sci_out(port, SCFCR, ctrl);
+ }
sci_out(port, SCSCR, s->cfg->scscr);
@@ -1892,6 +2025,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
struct uart_port *port = &sci_port->port;
int ret;
+ sci_port->cfg = p;
+
port->ops = &sci_uart_ops;
port->iotype = UPIO_MEM;
port->line = index;
@@ -1937,6 +2072,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
port->dev = &dev->dev;
+ sci_init_gpios(sci_port);
+
pm_runtime_irq_safe(&dev->dev);
pm_runtime_enable(&dev->dev);
}
@@ -1971,8 +2108,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
p->error_mask |= (1 << p->overrun_bit);
}
- sci_port->cfg = p;
-
port->mapbase = p->mapbase;
port->type = p->type;
port->flags = p->flags;
@@ -2113,9 +2248,16 @@ static int sci_runtime_suspend(struct device *dev)
struct uart_port *port = &sci_port->port;
if (uart_console(port)) {
+ struct plat_sci_reg *reg;
+
sci_port->saved_smr = sci_in(port, SCSMR);
sci_port->saved_brr = sci_in(port, SCBRR);
- sci_port->saved_fcr = sci_in(port, SCFCR);
+
+ reg = sci_getreg(port, SCFCR);
+ if (reg->size)
+ sci_port->saved_fcr = sci_in(port, SCFCR);
+ else
+ sci_port->saved_fcr = 0;
}
return 0;
}
@@ -2129,7 +2271,10 @@ static int sci_runtime_resume(struct device *dev)
sci_reset(port);
sci_out(port, SCSMR, sci_port->saved_smr);
sci_out(port, SCBRR, sci_port->saved_brr);
- sci_out(port, SCFCR, sci_port->saved_fcr);
+
+ if (sci_port->saved_fcr)
+ sci_out(port, SCFCR, sci_port->saved_fcr);
+
sci_out(port, SCSCR, sci_port->cfg->scscr);
}
return 0;
@@ -2169,6 +2314,8 @@ static int sci_remove(struct platform_device *dev)
cpufreq_unregister_notifier(&port->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
+ sci_free_gpios(port);
+
uart_remove_one_port(&sci_uart_driver, &port->port);
clk_put(port->iclk);
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index 369273a..7877907 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -49,6 +49,10 @@ enum {
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+/* SCSPTR, optional */
+#define SCSPTR_RTSIO (1 << 7)
+#define SCSPTR_CTSIO (1 << 5)
+
/* Offsets into the sci_port->irqs array */
enum {
SCIx_ERI_IRQ,
@@ -60,6 +64,17 @@ enum {
SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
};
+/* Offsets into the sci_port->gpios array */
+enum {
+ SCIx_SCK,
+ SCIx_RXD,
+ SCIx_TXD,
+ SCIx_CTS,
+ SCIx_RTS,
+
+ SCIx_NR_FNS,
+};
+
enum {
SCIx_PROBE_REGTYPE,
@@ -109,13 +124,20 @@ struct plat_sci_port_ops {
};
/*
+ * Port-specific capabilities
+ */
+#define SCIx_HAVE_RTSCTS (1 << 0)
+
+/*
* Platform device specific platform_data struct
*/
struct plat_sci_port {
unsigned long mapbase; /* resource base */
unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */
+ unsigned int gpios[SCIx_NR_FNS]; /* SCK, RXD, TXD, CTS, RTS */
unsigned int type; /* SCI / SCIF / IRDA */
upf_t flags; /* UPF_* flags */
+ unsigned long capabilities; /* Port features/capabilities */
unsigned int scbrr_algo_id; /* SCBRR calculation algo */
unsigned int scscr; /* SCSCR initialization */
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index a20831c..54341d8 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -49,6 +49,7 @@ struct clk {
void __iomem *enable_reg;
unsigned int enable_bit;
+ void __iomem *mapped_reg;
unsigned long arch_flags;
void *priv;
@@ -131,10 +132,9 @@ int sh_clk_div4_enable_register(struct clk *clks, int nr,
int sh_clk_div4_reparent_register(struct clk *clks, int nr,
struct clk_div4_table *table);
-#define SH_CLK_DIV6_EXT(_parent, _reg, _flags, _parents, \
+#define SH_CLK_DIV6_EXT(_reg, _flags, _parents, \
_num_parents, _src_shift, _src_width) \
{ \
- .parent = _parent, \
.enable_reg = (void __iomem *)_reg, \
.flags = _flags, \
.parent_table = _parents, \
@@ -144,7 +144,11 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
}
#define SH_CLK_DIV6(_parent, _reg, _flags) \
- SH_CLK_DIV6_EXT(_parent, _reg, _flags, NULL, 0, 0, 0)
+{ \
+ .parent = _parent, \
+ .enable_reg = (void __iomem *)_reg, \
+ .flags = _flags, \
+}
int sh_clk_div6_register(struct clk *clks, int nr);
int sh_clk_div6_reparent_register(struct clk *clks, int nr);
diff --git a/include/linux/sh_pfc.h b/include/linux/sh_pfc.h
index 8446789..91666a5 100644
--- a/include/linux/sh_pfc.h
+++ b/include/linux/sh_pfc.h
@@ -55,6 +55,7 @@ struct pinmux_cfg_reg {
struct pinmux_data_reg {
unsigned long reg, reg_width, reg_shadow;
pinmux_enum_t *enum_ids;
+ void __iomem *mapped_reg;
};
#define PINMUX_DATA_REG(name, r, r_width) \
@@ -75,6 +76,12 @@ struct pinmux_range {
pinmux_enum_t force;
};
+struct pfc_window {
+ phys_addr_t phys;
+ void __iomem *virt;
+ unsigned long size;
+};
+
struct pinmux_info {
char *name;
pinmux_enum_t reserved_id;
@@ -98,6 +105,10 @@ struct pinmux_info {
struct pinmux_irq *gpio_irq;
unsigned int gpio_irq_size;
+ struct resource *resource;
+ unsigned int num_resources;
+ struct pfc_window *window;
+
struct gpio_chip chip;
};