Merge branch 'rmobile-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6

* 'rmobile-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6:
  ARM: mach-shmobile: clock-sh7372: remove bogus pllc2 clock toggling.
  ARM: mach-shmobile: clock-sh7372: remove unnecessary fsi clocks
  ARM: mach-shmobile: clock-sh7372: modify error code
  ARM: mach-shmobile: ap4evb: FSI clock use proper process for ak4642
  ARM: mach-shmobile: ap4evb: FSI clock use proper process for HDMI
  ARM: mach-shmobile: clock-sh7372: remove fsidiv bogus disable
  ARM: mach-shmobile: sh7372 USB0/IIC1 MSTP fix
This commit is contained in:
Linus Torvalds 2010-11-27 07:17:16 +09:00
commit d4d2ad948e
4 changed files with 140 additions and 71 deletions

View File

@ -567,38 +567,127 @@ static struct platform_device *qhd_devices[] __initdata = {
/* FSI */ /* FSI */
#define IRQ_FSI evt2irq(0x1840) #define IRQ_FSI evt2irq(0x1840)
static int __fsi_set_rate(struct clk *clk, long rate, int enable)
{
int ret = 0;
static int fsi_set_rate(int is_porta, int rate) if (rate <= 0)
return ret;
if (enable) {
ret = clk_set_rate(clk, rate);
if (0 == ret)
ret = clk_enable(clk);
} else {
clk_disable(clk);
}
return ret;
}
static int __fsi_set_round_rate(struct clk *clk, long rate, int enable)
{
return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable);
}
static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable)
{
struct clk *fsia_ick;
struct clk *fsiack;
int ret = -EIO;
fsia_ick = clk_get(dev, "icka");
if (IS_ERR(fsia_ick))
return PTR_ERR(fsia_ick);
/*
* FSIACK is connected to AK4642,
* and use external clock pin from it.
* it is parent of fsia_ick now.
*/
fsiack = clk_get_parent(fsia_ick);
if (!fsiack)
goto fsia_ick_out;
/*
* we get 1/1 divided clock by setting same rate to fsiack and fsia_ick
*
** FIXME **
* Because the freq_table of external clk (fsiack) are all 0,
* the return value of clk_round_rate became 0.
* So, it use __fsi_set_rate here.
*/
ret = __fsi_set_rate(fsiack, rate, enable);
if (ret < 0)
goto fsiack_out;
ret = __fsi_set_round_rate(fsia_ick, rate, enable);
if ((ret < 0) && enable)
__fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */
fsiack_out:
clk_put(fsiack);
fsia_ick_out:
clk_put(fsia_ick);
return 0;
}
static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable)
{ {
struct clk *fsib_clk; struct clk *fsib_clk;
struct clk *fdiv_clk = &sh7372_fsidivb_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk;
long fsib_rate = 0;
long fdiv_rate = 0;
int ackmd_bpfmd;
int ret; int ret;
/* set_rate is not needed if port A */
if (is_porta)
return 0;
fsib_clk = clk_get(NULL, "fsib_clk");
if (IS_ERR(fsib_clk))
return -EINVAL;
switch (rate) { switch (rate) {
case 44100: case 44100:
clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000)); fsib_rate = rate * 256;
ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
break; break;
case 48000: case 48000:
clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000)); fsib_rate = 85428000; /* around 48kHz x 256 x 7 */
clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000)); fdiv_rate = rate * 256;
ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
break; break;
default: default:
pr_err("unsupported rate in FSI2 port B\n"); pr_err("unsupported rate in FSI2 port B\n");
ret = -EINVAL; return -EINVAL;
break;
} }
/* FSI B setting */
fsib_clk = clk_get(dev, "ickb");
if (IS_ERR(fsib_clk))
return -EIO;
ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable);
clk_put(fsib_clk); clk_put(fsib_clk);
if (ret < 0)
return ret;
/* FSI DIV setting */
ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable);
if (ret < 0) {
/* disable FSI B */
if (enable)
__fsi_set_round_rate(fsib_clk, fsib_rate, 0);
return ret;
}
return ackmd_bpfmd;
}
static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
{
int ret;
if (is_porta)
ret = fsi_ak4642_set_rate(dev, rate, enable);
else
ret = fsi_hdmi_set_rate(dev, rate, enable);
return ret; return ret;
} }
@ -880,6 +969,11 @@ static int __init hdmi_init_pm_clock(void)
goto out; goto out;
} }
ret = clk_enable(&sh7372_pllc2_clk);
if (ret < 0) {
pr_err("Cannot enable pllc2 clock\n");
goto out;
}
pr_debug("PLLC2 set frequency %lu\n", rate); pr_debug("PLLC2 set frequency %lu\n", rate);
ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@ -896,23 +990,11 @@ static int __init hdmi_init_pm_clock(void)
device_initcall(hdmi_init_pm_clock); device_initcall(hdmi_init_pm_clock);
#define FSIACK_DUMMY_RATE 48000
static int __init fsi_init_pm_clock(void) static int __init fsi_init_pm_clock(void)
{ {
struct clk *fsia_ick; struct clk *fsia_ick;
int ret; int ret;
/*
* FSIACK is connected to AK4642,
* and the rate is depend on playing sound rate.
* So, set dummy rate (= 48k) here
*/
ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE);
if (ret < 0) {
pr_err("Cannot set FSIACK dummy rate: %d\n", ret);
return ret;
}
fsia_ick = clk_get(&fsi_device.dev, "icka"); fsia_ick = clk_get(&fsi_device.dev, "icka");
if (IS_ERR(fsia_ick)) { if (IS_ERR(fsia_ick)) {
ret = PTR_ERR(fsia_ick); ret = PTR_ERR(fsia_ick);
@ -921,16 +1003,9 @@ static int __init fsi_init_pm_clock(void)
} }
ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk);
if (ret < 0) {
pr_err("Cannot set FSI-A parent: %d\n", ret);
goto out;
}
ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE);
if (ret < 0) if (ret < 0)
pr_err("Cannot set FSI-A rate: %d\n", ret); pr_err("Cannot set FSI-A parent: %d\n", ret);
out:
clk_put(fsia_ick); clk_put(fsia_ick);
return ret; return ret;

View File

@ -229,21 +229,13 @@ static int pllc2_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0) if (idx < 0)
return idx; return idx;
if (rate == clk->parent->rate) { if (rate == clk->parent->rate)
pllc2_disable(clk); return -EINVAL;
return 0;
}
value = __raw_readl(PLLC2CR) & ~(0x3f << 24); value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
if (value & 0x80000000)
pllc2_disable(clk);
__raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR); __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
if (value & 0x80000000)
return pllc2_enable(clk);
return 0; return 0;
} }
@ -452,10 +444,8 @@ static int fsidiv_enable(struct clk *clk)
unsigned long value; unsigned long value;
value = __raw_readl(clk->mapping->base) >> 16; value = __raw_readl(clk->mapping->base) >> 16;
if (value < 2) { if (value < 2)
fsidiv_disable(clk); return -EIO;
return -ENOENT;
}
__raw_writel((value << 16) | 0x3, clk->mapping->base); __raw_writel((value << 16) | 0x3, clk->mapping->base);
@ -466,17 +456,12 @@ static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
{ {
int idx; int idx;
if (clk->parent->rate == rate) {
fsidiv_disable(clk);
return 0;
}
idx = (clk->parent->rate / rate) & 0xffff; idx = (clk->parent->rate / rate) & 0xffff;
if (idx < 2) if (idx < 2)
return -ENOENT; return -EINVAL;
__raw_writel(idx << 16, clk->mapping->base); __raw_writel(idx << 16, clk->mapping->base);
return fsidiv_enable(clk); return 0;
} }
static struct clk_ops fsidiv_clk_ops = { static struct clk_ops fsidiv_clk_ops = {
@ -607,8 +592,6 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]),
CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]),
CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
@ -645,8 +628,8 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */

View File

@ -85,7 +85,9 @@
* ACK_MD (FSI2) * ACK_MD (FSI2)
* CKG1 (FSI) * CKG1 (FSI)
* *
* err: return value < 0 * err : return value < 0
* no change : return value == 0
* change xMD : return value > 0
* *
* 0x-00000AB * 0x-00000AB
* *
@ -111,7 +113,7 @@
struct sh_fsi_platform_info { struct sh_fsi_platform_info {
unsigned long porta_flags; unsigned long porta_flags;
unsigned long portb_flags; unsigned long portb_flags;
int (*set_rate)(int is_porta, int rate); /* for master mode */ int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
}; };
#endif /* __SOUND_FSI_H */ #endif /* __SOUND_FSI_H */

View File

@ -132,6 +132,8 @@ struct fsi_priv {
struct fsi_stream playback; struct fsi_stream playback;
struct fsi_stream capture; struct fsi_stream capture;
long rate;
u32 mst_ctrl; u32 mst_ctrl;
}; };
@ -854,10 +856,17 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
{ {
struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_priv *fsi = fsi_get_priv(substream);
int is_play = fsi_is_play(substream); int is_play = fsi_is_play(substream);
struct fsi_master *master = fsi_get_master(fsi);
int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
fsi_irq_disable(fsi, is_play); fsi_irq_disable(fsi, is_play);
fsi_clk_ctrl(fsi, 0); fsi_clk_ctrl(fsi, 0);
set_rate = master->info->set_rate;
if (set_rate && fsi->rate)
set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
fsi->rate = 0;
pm_runtime_put_sync(dai->dev); pm_runtime_put_sync(dai->dev);
} }
@ -891,20 +900,20 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
{ {
struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_priv *fsi = fsi_get_priv(substream);
struct fsi_master *master = fsi_get_master(fsi); struct fsi_master *master = fsi_get_master(fsi);
int (*set_rate)(int is_porta, int rate) = master->info->set_rate; int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
int fsi_ver = master->core->ver; int fsi_ver = master->core->ver;
int is_play = fsi_is_play(substream); long rate = params_rate(params);
int ret; int ret;
/* if slave mode, set_rate is not needed */ set_rate = master->info->set_rate;
if (!fsi_is_master_mode(fsi, is_play)) if (!set_rate)
return 0; return 0;
/* it is error if no set_rate */ ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
if (!set_rate) if (ret < 0) /* error */
return -EIO; return ret;
ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); fsi->rate = rate;
if (ret > 0) { if (ret > 0) {
u32 data = 0; u32 data = 0;