static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt) { unsigned long tcon; tcon = __raw_readl(S3C2410_TCON); /* timers reload after counting zero, so reduce the count by 1 */ tcnt--; /* ensure timer is stopped... */ switch (pwm_id) { case 2: tcon &= ~(0xf<<12); tcon |= S3C2410_TCON_T2MANUALUPD; __raw_writel(tcnt, S3C2410_TCNTB(2)); __raw_writel(tcnt, S3C2410_TCMPB(2)); __raw_writel(tcon, S3C2410_TCON); break; case 4: tcon &= ~(7<<20); tcon |= S3C2410_TCON_T4MANUALUPD; __raw_writel(tcnt, S3C2410_TCNTB(4)); __raw_writel(tcnt, S3C2410_TCMPB(4)); __raw_writel(tcon, S3C2410_TCON); break; default: break; } }
static inline void s3c64xx_pwm_reconfigure(unsigned int pwm_id, unsigned long tcnt, bool periodic) { unsigned long tcon = __raw_readl(S3C2410_TCON); switch (pwm_id) { case 3: tcon |= S3C2410_TCON_T3START; tcon &= ~S3C2410_TCON_T3MANUALUPD; if (periodic) tcon |= S3C2410_TCON_T3RELOAD; else tcon &= ~S3C2410_TCON_T3RELOAD; break; case 4: tcon |= S3C2410_TCON_T4START; tcon &= ~S3C2410_TCON_T4MANUALUPD; if (periodic) tcon |= S3C2410_TCON_T4RELOAD; else tcon &= ~S3C2410_TCON_T4RELOAD; break; } __raw_writel(tcnt, S3C2410_TCNTB(pwm_id)); __raw_writel(tcnt, S3C2410_TCMPB(pwm_id)); __raw_writel(tcon, S3C2410_TCON); }
static void s3c210_set_timer1(unsigned long Val) { #if 0 //#ifdef CONFIG_S3C210_PWM s3c_gpio_cfgpin(S3C64XX_GPF(15),S3C64XX_GPF15_PWM_TOUT1); pwm_config(beeper->pwm, beeper->step_ns*Val, beeper->period); #else unsigned long tcon;//用于存放时钟控制寄存器的数值 unsigned long tcnt;//用于存放TCNTB1的数值 unsigned long tcmp;//用于存放TCMPB1的数值 unsigned long tcfg1;//用于存放定时器配置寄存器1的数值 unsigned long tcfg0;//用于存放定时器配置寄存器0的数值 unsigned char i; tcnt = 0xffffffff; /* 默认的TCTB1数值*/ /* 读取TCON,TCFG0以及TCFG1寄存器的数值*/ tcon = __raw_readl(S3C2410_TCON); tcfg1 =__raw_readl(S3C2410_TCFG1); tcfg0 =__raw_readl(S3C2410_TCFG0); /*定时器输入频率 = PCLK / ( {预分频数值 + 1} ) / {分割数值} *{预分频数值} = 1~255,由TCFG0配置寄存器来配置 *{分割数值} = 1, 2, 4, 8, 16, TCLK,由TCFG1配置寄存器来配置 */ //配置GPF15为输出 for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++) { s3c_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]); s3c_gpio_setpull(gpio_table[i], S3C_GPIO_PULL_NONE); } //清零TCFG1[4:7] tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK; //设置分割值为2 tcfg1 |= S3C2410_TCFG1_MUX1_DIV2;//set [4:7]== 1/2 //清零预分频位TCFG0[0:7] tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; //设置预分频数值,这里是254 // tcfg0 |= (PRESCALER) << 0;//backlight pwm0 //清零TCON[8:10] tcon &= ~(7<<8); //set bit [8:10] to zero //设置定时器工作模式为自动加载模式(auto-reload) tcon |= S3C2410_TCON_T1RELOAD; //将配置好的TCON,TCFG0,TCFG1的数值写回寄存器 __raw_writel(tcfg1, S3C2410_TCFG1); // __raw_writel(tcfg0, S3C2410_TCFG0);//backlight pwm0 div __raw_writel(tcon, S3C2410_TCON); //准备更新TCMPB1数值,先置1 TCON[9] tcon |= S3C2410_TCON_T1MANUALUPD; __raw_writel(tcon, S3C2410_TCON); //TCNTB1==200,改数值决定了PWM的频率 tcnt = 101*255; __raw_writel(tcnt, S3C2410_TCNTB(1)); //改变TCMPB1的数值,改数值决定PWM的频宽 tcmp = Val*255; __raw_writel(tcmp, S3C2410_TCMPB(1)); #endif }
static int tq2440_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long tcfg0; unsigned long tcfg1; unsigned long tcntb; unsigned long tcmpb; unsigned long tcon; switch (cmd) { case BEEP_OFF: s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT); s3c2410_gpio_setpin(S3C2410_GPB(0), 0); break; case BEEP_ON_TIMES: { void __user *argp = (void __user *)arg; unsigned int args = *((unsigned int *)argp); struct clk *clk_p; unsigned long pclk; //set GPB0 as tout0, pwm output s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); //prescaler = 50 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (50 - 1); //mux = 1/16 tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); clk_p = clk_get(NULL, "pclk"); pclk = clk_get_rate(clk_p); tcntb = (pclk/128)/args; tcmpb = tcntb>>1; __raw_writel(tcntb, S3C2410_TCNTB(0)); __raw_writel(tcmpb, S3C2410_TCMPB(0)); tcon &= ~0x1f; tcon |= 0xb; //start timer __raw_writel(tcon, S3C2410_TCON); tcon &= ~2; __raw_writel(tcon, S3C2410_TCON); } break; } return 0; }
static long tq2440_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned long tcfg0; unsigned long tcfg1; unsigned long tcntb; unsigned long tcmpb; unsigned long tcon; mutex_lock(&tq2440bzr_mutex); if(cmd <= 0) { s3c_gpio_cfgpin(S3C2410_GPB(0), S3C_GPIO_OUTPUT); gpio_set_value(S3C2410_GPB(0), 0); } else { struct clk *clk_p; unsigned long pclk; //set GPB0 as tout0, pwm output s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); //prescaler = 50 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (50 - 1); //mux = 1/16 tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); clk_p = clk_get(NULL, "pclk"); pclk = clk_get_rate(clk_p); tcntb = (pclk/128)/arg; tcmpb = tcntb>>1; __raw_writel(tcntb, S3C2410_TCNTB(0)); __raw_writel(tcmpb, S3C2410_TCMPB(0)); tcon &= ~0x1f; tcon |= 0xb; //start timer __raw_writel(tcon, S3C2410_TCON); tcon &= ~2; __raw_writel(tcon, S3C2410_TCON); } mutex_unlock(&tq2440bzr_mutex); return 0; }
/* freq: pclk/50/16/65536 ~ pclk/50/16/1 * if pclk = 50MHz, freq is 1Hz to 62500Hz * human ear : 20Hz~ 20000Hz */ static void PWM_Set_Freq( unsigned long freq ) { unsigned long tcon=0; unsigned long tcnt=0; unsigned long tcfg1=0; unsigned long tcfg0=0; struct clk *clk_p=0; unsigned long pclk=1; unsigned tmp; freq=freq>0?freq:1; printk ("in module Freq is %d\n",freq); tmp = readl(GPD0CON);//PWM out use timer0 TOUT_0 here tmp &=~(0xfU);// TOUT_0 here tmp |= (0x2U); //use TOUT_0 writel(tmp, GPD0CON);// Set hightest bit is '10' to pwm out tcon = __raw_readl(S5PV210_TCON); tcfg1 = __raw_readl(S5PV210_TCFG1); tcfg0 = __raw_readl(S5PV210_TCFG0); //prescaler = 50 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;//S3C_TCFG_PRESCALER0_MASK; tcfg0 |= (50 - 1); //mux = 1/16 tcfg1 &= ~S5PV210_TCFG1_MUX1_MASK ;//S3C_TCFG1_MUX1_MASK; tcfg1 |= S5PV210_TCFG1_MUX1_DIV16;//S3C_TCFG1_MUX1_DIV16; __raw_writel(tcfg1, S5PV210_TCFG1); __raw_writel(tcfg0, S5PV210_TCFG0); clk_p = clk_get(NULL, "pclk"); pclk = clk_get_rate(clk_p); tcnt = pclk/50/16/freq; printk ("in module pclk is %dHz\n", pclk); printk ("in module tcntb is %d \n",tcnt); __raw_writel(tcnt, S3C2410_TCNTB(0));//use timer0 tcntb __raw_writel(tcnt/2, S3C2410_TCMPB(0));//use timer0 tcmpb tcon &= ~(0xf); tcon |= (0xb); // set 3-0 bit of TCON is '1011' . auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0 __raw_writel(tcon, S5PV210_TCON); tcon &= ~(2); //set set 11-8 bit of S3C_TCON is '1001' __raw_writel(tcon, S5PV210_TCON); }
/**************************************************************************** * Backlight control ****************************************************************************/ void reciva_bl_set_backlight(int level) { if (level > 31) level = 31; /* Still get pulses if we set it to zero * Setting to 32 removes the pulses * XXX ideally need to work out why, but don't have time now */ if (level == 0) level = 32; __raw_writel (level, S3C2410_TCMPB(1)); }
/* freq: pclk/50/16/65536 ~ pclk/50/16 * if pclk = 50MHz, freq is 1Hz to 62500Hz * human ear : 20Hz~ 20000Hz */ static void PWM_Set_Freq( unsigned long freq ) { unsigned long tcon; unsigned long tcnt; unsigned long tcfg1; unsigned long tcfg0; struct clk *clk_p; unsigned long pclk; unsigned tmp; /* buzzer setup */ tmp = readl(S3C2410_GPBCON); tmp &= ~(0x3U); tmp |= (0x2U); writel(tmp, S3C2410_GPBCON); tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); /* prescaler = 50 */ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (50 - 1); /* mux = 1/16 */ tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); clk_p = clk_get(NULL, "pclk"); pclk = clk_get_rate(clk_p); tcnt = (pclk/50/16)/freq; __raw_writel(tcnt, S3C2410_TCNTB(0)); __raw_writel(tcnt/2, S3C2410_TCMPB(0)); tcon &= ~0x1f; //tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0 tcon |= (S3C2410_TCON_T0START | S3C2410_TCON_T0MANUALUPD | S3C2410_TCON_T0RELOAD); __raw_writel(tcon, S3C2410_TCON); //tcon &= ~2; //clear manual update bit tcon &= ~S3C2410_TCON_T0MANUALUPD; __raw_writel(tcon, S3C2410_TCON); }
/**************************************************************************** * Backlight control ****************************************************************************/ void reciva_bl_set_backlight(int level) { if (level < 0 ) level = 0; else if (level > BL_DEFAULT_MAX_BACKLIGHT) level = BL_DEFAULT_MAX_BACKLIGHT; /* NB. This solves the same issue as different code in * reciva_backlight_potas.c. The two modules could probably be merged in * future, in which case, only one solution is required. */ /* Still get pulses if we set it to zero * Setting to 32 removes the pulses * XXX ideally need to work out why, but don't have time now */ if (level == 0) level = 32; __raw_writel (level, S3C2410_TCMPB(1)); }
static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt) { unsigned long tcon; tcon = __raw_readl(S3C2410_TCON); tcnt--; switch (mode) { case S5P_PWM0: tcon &= ~(0x0f << 0); tcon |= S3C2410_TCON_T0MANUALUPD; break; case S5P_PWM1: tcon &= ~(0x0f << 8); tcon |= S3C2410_TCON_T1MANUALUPD; break; case S5P_PWM2: tcon &= ~(0x0f << 12); tcon |= S3C2410_TCON_T2MANUALUPD; break; case S5P_PWM3: tcon &= ~(0x0f << 16); tcon |= S3C2410_TCON_T3MANUALUPD; break; case S5P_PWM4: tcon &= ~(0x07 << 20); tcon |= S3C2410_TCON_T4MANUALUPD; break; default: printk(KERN_ERR "Invalid Timer %d\n", mode); break; } __raw_writel(tcnt, S3C2410_TCNTB(mode)); __raw_writel(tcnt, S3C2410_TCMPB(mode)); __raw_writel(tcon, S3C2410_TCON); }
static int buzzer_ioctl (struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) { if (cmd <= 0) { s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_OUTP);//关闭蜂鸣器 s3c2410_gpio_setpin(S3C2410_GPB0,0); } else { unsigned long tcnt = 0; unsigned long tcon = 0; unsigned long tcfg0 = 0; unsigned long tcfg1 = 0; unsigned long pclk = 0; tcfg0 = __raw_readl(S3C2410_TCFG0); //定时器配置寄存器 tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; //相应位清零 tcfg0 |= (50-1);//49 定时器预分频值 tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; //相应位清零 tcfg1 |= S3C2410_TCFG1_MUX0_DIV4;//1/4 分频值 PWM定时器0选通选择DIV4 __raw_writel(tcfg0,S3C2410_TCFG0);//写入寄存器 __raw_writel(tcfg1,S3C2410_TCFG1); pclk = 50000000; //时钟50MHZ tcnt = (pclk/50/4)/cmd;//计算对应cmd频率的定时计数器值 定时器控制寄存器 PCLK/预分频值 + 1(0~255)/分频值 __raw_writel(tcnt,S3C2410_TCNTB(0));//定时器0计数缓冲寄存器 __raw_writel(tcnt/2,S3C2410_TCMPB(0)); //定时器0比较缓冲器 tcon = __raw_readl(S3C2410_TCON); tcon &= ~0x1f; //00011111 相应位清零 tcon |= 0xb;//禁止死区0,自动重载1,关闭变相0,更新1,启动定时器1 01011 __raw_writel(tcon,S3C2410_TCON); tcon &= ~0x2;//清除手动更新//0010 __raw_writel(tcon,S3C2410_TCON); } return 0; }
static void s3c64xx_sched_timer_start(unsigned long load_val, int autoreset) { unsigned long tcon; unsigned long tcnt; unsigned long tcfg1; unsigned long tcfg0; unsigned long tcstat; tcstat = __raw_readl(S3C64XX_TINT_CSTAT); tcstat |= 0x04; __raw_writel(tcstat, S3C64XX_TINT_CSTAT); tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); tcnt = load_val; tcnt--; __raw_writel(tcnt, S3C2410_TCNTB(2)); __raw_writel(tcnt, S3C2410_TCMPB(2)); tcon &= ~(0x0b<<12); if (autoreset) tcon |= S3C2410_TCON_T2RELOAD; tcon |= S3C2410_TCON_T2MANUALUPD; __raw_writel(tcon, S3C2410_TCON); /* start the timer running */ tcon |= S3C2410_TCON_T2START; tcon &= ~S3C2410_TCON_T2MANUALUPD; __raw_writel(tcon, S3C2410_TCON); }
static inline void s3c64xx_pwm_init(unsigned int pwm_id, unsigned long tcnt) { unsigned long tcon = __raw_readl(S3C2410_TCON); /* timers reload after counting zero, so reduce the count by 1 */ --tcnt; /* stop the timer and ask it to load the new value */ switch (pwm_id) { case 3: tcon &= ~(0xf<<16); tcon |= S3C2410_TCON_T3MANUALUPD; break; case 4: tcon &= ~(7<<20); tcon |= S3C2410_TCON_T4MANUALUPD; break; } __raw_writel(tcnt, S3C2410_TCNTB(pwm_id)); __raw_writel(tcnt, S3C2410_TCMPB(pwm_id)); __raw_writel(tcon, S3C2410_TCON); }
SAVE_ITEM(S5P_CLKGATE_IP2), SAVE_ITEM(S5P_CLKGATE_IP3), SAVE_ITEM(S5P_CLKGATE_IP4), /* Clock Blcok and Bus gate */ SAVE_ITEM(S5P_CLKGATE_BLOCK), SAVE_ITEM(S5P_CLKGATE_IP5), /* Clock ETC */ SAVE_ITEM(S5P_CLK_OUT), SAVE_ITEM(S5P_MDNIE_SEL), /* PWM Register */ SAVE_ITEM(S3C2410_TCFG0), SAVE_ITEM(S3C2410_TCFG1), SAVE_ITEM(S3C64XX_TINT_CSTAT), SAVE_ITEM(S3C2410_TCON), SAVE_ITEM(S3C2410_TCNTB(0)), SAVE_ITEM(S3C2410_TCMPB(0)), SAVE_ITEM(S3C2410_TCNTO(0)), }; static struct sleep_save sromc_save[] = { SAVE_ITEM(S5P_SROM_BW), SAVE_ITEM(S5P_SROM_BC0), SAVE_ITEM(S5P_SROM_BC1), SAVE_ITEM(S5P_SROM_BC2), SAVE_ITEM(S5P_SROM_BC3), SAVE_ITEM(S5P_SROM_BC4), SAVE_ITEM(S5P_SROM_BC5), }; /* s3c_pm_check_resume_pin *
static void GPTimerSetValue(unsigned long load,unsigned long cmp) { __raw_writel(load, S3C2410_TCNTB(1)); __raw_writel(cmp, S3C2410_TCMPB(1)); }
static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct s3c_chip *s3c = to_s3c_chip(chip); unsigned long tin_rate; unsigned long tin_ns; unsigned long period; unsigned long flags; unsigned long tcon; unsigned long tcnt; long tcmp; /* We currently avoid using 64bit arithmetic by using the * fact that anything faster than 1Hz is easily representable * by 32bits. */ if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) return -ERANGE; if (duty_ns > period_ns) return -EINVAL; if (period_ns == s3c->period_ns && duty_ns == s3c->duty_ns) return 0; /* The TCMP and TCNT can be read without a lock, they're not * shared between the timers. */ tcmp = __raw_readl(S3C2410_TCMPB(s3c->pwm_id)); tcnt = __raw_readl(S3C2410_TCNTB(s3c->pwm_id)); period = NS_IN_HZ / period_ns; pwm_dbg(s3c, "duty_ns=%d, period_ns=%d (%lu)\n", duty_ns, period_ns, period); /* Check to see if we are changing the clock rate of the PWM */ if (s3c->period_ns != period_ns) { if (pwm_is_tdiv(s3c)) { tin_rate = pwm_calc_tin(s3c, period); clk_set_rate(s3c->clk_div, tin_rate); } else tin_rate = clk_get_rate(s3c->clk); s3c->period_ns = period_ns; pwm_dbg(s3c, "tin_rate=%lu\n", tin_rate); tin_ns = NS_IN_HZ / tin_rate; tcnt = period_ns / tin_ns; } else tin_ns = NS_IN_HZ / clk_get_rate(s3c->clk); /* Note, counters count down */ tcmp = duty_ns / tin_ns; tcmp = tcnt - tcmp; /* the pwm hw only checks the compare register after a decrement, so the pin never toggles if tcmp = tcnt */ if (tcmp == tcnt) tcmp--; pwm_dbg(s3c, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); if (tcmp < 0) tcmp = 0; /* Update the PWM register block. */ local_irq_save(flags); __raw_writel(tcmp, S3C2410_TCMPB(s3c->pwm_id)); __raw_writel(tcnt, S3C2410_TCNTB(s3c->pwm_id)); tcon = __raw_readl(S3C2410_TCON); tcon |= pwm_tcon_manulupdate(s3c); tcon |= pwm_tcon_autoreload(s3c); __raw_writel(tcon, S3C2410_TCON); tcon &= ~pwm_tcon_manulupdate(s3c); __raw_writel(tcon, S3C2410_TCON); local_irq_restore(flags); return 0; }
static int PWM_open(struct inode *inode, struct file *file) { struct clk *clk_p; unsigned long pclk; s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); s3c2410_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1); s3c2410_gpio_cfgpin(S3C2410_GPB(2), S3C2410_GPB2_TOUT2); s3c2410_gpio_cfgpin(S3C2410_GPB(3), S3C2410_GPB3_TOUT3); tcon = __raw_readl(S3C2410_TCON); tcfg0 = __raw_readl(S3C2410_TCFG0); tcfg1 = __raw_readl(S3C2410_TCFG1); //设置TCFG0寄存器,prescaler = 50 //Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value} tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; // S3C2410_TCFG_PRESCALER0_MASK 定时器 0 和1 的预分频值的掩码,清除TCFG[0~8] tcfg0 |= (100 - 1); // 设置预分频为 50 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; // S3C2410_TCFG_PRESCALER0_MASK 定时器 2 3 4 的预分频值的掩码,清除TCFG[0~8] tcfg0 |= (100 - 1) << 8; // 设置预分频为 50 tcfg1 &= ~(S3C2410_TCFG1_MUX0_MASK | S3C2410_TCFG1_MUX1_MASK | S3C2410_TCFG1_MUX2_MASK | S3C2410_TCFG1_MUX3_MASK); tcfg1 |= S3C2410_TCFG1_MUX0_DIV16 | S3C2410_TCFG1_MUX1_DIV16 | S3C2410_TCFG1_MUX2_DIV16 | S3C2410_TCFG1_MUX3_DIV16; __raw_writel(tcfg1, S3C2410_TCFG1); //把 tcfg1 的值写到分割寄存器 S3C2410_TCFG1 中 __raw_writel(tcfg0, S3C2410_TCFG0); //把 tcfg0 的值写到预分频寄存器 S3C2410_TCFG0 中 clk_p = clk_get(NULL, "pclk"); //得到 pclk pclk = clk_get_rate(clk_p); PDEBUG("plck %ld \n",pclk); tcnt[0] = (pclk/100/16)/1; tcmp[0] = tcnt[0]/2; tcnt[3] = tcnt[2] = tcnt[1] = tcnt[0]; tcmp[3] = tcmp[2] = tcmp[1] = tcmp[0]; __raw_writel(tcnt[0], S3C2410_TCNTB(0)); __raw_writel(tcmp[0], S3C2410_TCMPB(0));//tcnt[0] tcmp[0] 4000 __raw_writel(tcnt[0], S3C2410_TCNTB(1)); __raw_writel(tcmp[0], S3C2410_TCMPB(1)); __raw_writel(tcnt[0], S3C2410_TCNTB(2)); __raw_writel(tcmp[0], S3C2410_TCMPB(2)); __raw_writel(tcnt[0], S3C2410_TCNTB(3)); __raw_writel(tcmp[0], S3C2410_TCMPB(3)); tcon &= ~(S3C2410_TCON_T0DEADZONE | S3C2410_TCON_T0INVERT); tcon |= S3C2410_TCON_T0RELOAD | S3C2410_TCON_T0MANUALUPD |S3C2410_TCON_T0START; tcon &= ~(S3C2410_TCON_T1INVERT); tcon |= S3C2410_TCON_T1RELOAD | S3C2410_TCON_T1MANUALUPD |S3C2410_TCON_T1START; tcon &= ~(S3C2410_TCON_T2INVERT); tcon |= S3C2410_TCON_T2RELOAD | S3C2410_TCON_T2MANUALUPD |S3C2410_TCON_T2START; tcon &= ~(S3C2410_TCON_T3INVERT); tcon |= S3C2410_TCON_T3RELOAD | S3C2410_TCON_T3MANUALUPD |S3C2410_TCON_T3START; __raw_writel(tcon, S3C2410_TCON); tcon &= ~(S3C2410_TCON_T0MANUALUPD | S3C2410_TCON_T1MANUALUPD | S3C2410_TCON_T2MANUALUPD | S3C2410_TCON_T3MANUALUPD); __raw_writel(tcon, S3C2410_TCON); return 0; }
/* * Set up timer interrupt, and return the current time in seconds. * * Currently we only use timer4, as it is the only timer which has no * other function that can be exploited externally */ void __init s3c2410_init_time (void) { unsigned long tcon; unsigned long tcnt; unsigned long tcfg1; unsigned long tcfg0; gettimeoffset = s3c2410_gettimeoffset; tcnt = 0xffff; /* default value for tcnt */ /* read the current timer configuration bits */ tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); /* configure the system for whichever machine is in use */ if (machine_is_bast() || machine_is_vr1000()) { timer_ticks_usec = 12; /* timer is at 12MHz */ tcnt = (timer_ticks_usec * (1000*1000)) / HZ; } /* for the h1940, we use the pclk from the core to generate * the timer values. since 67.5MHz is not a value we can directly * generate the timer value from, we need to pre-scale and * divied before using it. * * overall divsior to get 200Hz is 337500 * we can fit tcnt if we pre-scale by 6, producing a tick rate * of 11.25MHz, and a tcnt of 56250. */ if (machine_is_h1940() || machine_is_smdk2410() ) { timer_ticks_usec = s3c2410_pclk / (1000*1000); timer_ticks_usec /= 6; tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; tcnt = (s3c2410_pclk / 6) / HZ; } printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n", tcon, tcnt, tcfg0, tcfg1); /* check to see if timer is within 16bit range... */ if (tcnt > 0xffff) { panic("setup_timer: HZ is too small, cannot configure timer!"); return; } __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); timer_startval = tcnt; __raw_writel(tcnt, S3C2410_TCNTB(4)); /* ensure timer is stopped... */ tcon &= ~(7<<20); tcon |= S3C2410_TCON_T4RELOAD; tcon |= S3C2410_TCON_T4MANUALUPD; __raw_writel(tcon, S3C2410_TCON); __raw_writel(tcnt, S3C2410_TCNTB(4)); __raw_writel(tcnt, S3C2410_TCMPB(4)); setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); /* start the timer running */ tcon |= S3C2410_TCON_T4START; tcon &= ~S3C2410_TCON_T4MANUALUPD; __raw_writel(tcon, S3C2410_TCON); }
int s3c2450_timer_setup (int channel, int usec, unsigned long g_tcnt, unsigned long g_tcmp) { unsigned long tcon; unsigned long tcnt; unsigned long tcmp; unsigned long tcfg1; unsigned long tcfg0; unsigned long pclk; struct clk *clk; printk("\n\nPWM channel %d set g_tcnt = %ld, g_tcmp = %ld \n\n", channel, g_tcnt, g_tcmp); tcnt = 0xffffffff; /* default value for tcnt */ tcmp = 0; /* read the current timer configuration bits */ tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); clk = clk_get(NULL, "timers"); if (IS_ERR(clk)) panic("failed to get clock for pwm timer"); clk_enable(clk); pclk = clk_get_rate(clk); /* configure clock tick */ switch(channel) { case 0: /* set gpio as PWM TIMER0 to signal output*/ s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0); s3c2410_gpio_setpin(S3C2410_GPB0, 0); tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV2; tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (4) << 0; tcon &= ~(7<<0); tcon |= S3C2410_TCON_T0RELOAD; break; case 1: /* set gpio as PWM TIMER1 to signal output*/ s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_TOUT1); s3c2410_gpio_setpin(S3C2410_GPB1, 0); tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK; tcfg1 |= S3C2410_TCFG1_MUX1_DIV2; tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (4) << 0; tcon &= ~(7<<8); tcon |= S3C2410_TCON_T1RELOAD; break; case 2: s3c2410_gpio_cfgpin(S3C2410_GPB2, S3C2410_GPB2_TOUT2); s3c2410_gpio_setpin(S3C2410_GPB2, 0); tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK; tcfg1 |= S3C2410_TCFG1_MUX2_DIV2; tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; tcfg0 |= (4) << S3C2410_TCFG_PRESCALER1_SHIFT; tcon &= ~(7<<12); tcon |= S3C2410_TCON_T2RELOAD; break; case 3: s3c2410_gpio_cfgpin(S3C2410_GPB3, S3C2410_GPB3_TOUT3); s3c2410_gpio_setpin(S3C2410_GPB3, 0); tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK; tcfg1 |= S3C2410_TCFG1_MUX3_DIV2; tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; tcfg0 |= (4) << S3C2410_TCFG_PRESCALER1_SHIFT; tcon &= ~(7<<16); tcon |= S3C2410_TCON_T3RELOAD; break; } #if 0 tcnt = (pclk / ((PRESCALER)*DIVIDER)) / usec; printk("s3c2450 pwm timer tcnt=0x%08lx, pclk=0x%08lx, PRESCALER=%d, DIVIDER=%d, usec=%d\n", tcnt, pclk, PRESCALER, DIVIDER, usec); /* timers reload after counting zero, so reduce the count by 1 */ tcnt--; #endif __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); __raw_writel(tcon, S3C2410_TCON); #if 0 if (tcnt > 0xffffffff) { panic("setup_timer: HZ is too small, cannot configure timer!"); return 0; } #endif __raw_writel(tcnt, S3C2410_TCNTB(channel)); __raw_writel(tcmp, S3C2410_TCMPB(channel)); switch(channel) { case 0: tcon |= S3C2410_TCON_T0MANUALUPD; break; case 1: tcon |= S3C2410_TCON_T1MANUALUPD; break; case 2: tcon |= S3C2410_TCON_T2MANUALUPD; break; case 3: tcon |= S3C2410_TCON_T3MANUALUPD; break; } __raw_writel(tcon, S3C2410_TCON); tcnt = g_tcnt; __raw_writel(tcnt, S3C2410_TCNTB(channel)); tcmp = g_tcmp; __raw_writel(tcmp, S3C2410_TCMPB(channel)); /* start the timer running */ s3c2450_pwm_start (channel); return 0; }