/** * init_module() - This function is called when the module is loaded * * Return: On succes the function retuns a 0 (SUCCES). Otherwise a * negative number is returned. */ int init_module(void) { Major = register_chrdev(0, DEVICE_NAME, &fops); if (Major < 0) { printk(KERN_ALERT "Registering char device failed with %d\n", Major); return Major; } printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major); printk(KERN_INFO "the driver, create a device file with\n"); printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major); printk(KERN_INFO "Try various minor numbers. Try to echo to\n"); printk(KERN_INFO "the device file.\n"); printk(KERN_INFO "Remove the device file and module when done.\n"); gpio = (volatile unsigned int *)ioremap(GPIO_BASE, 1024); pwm = (volatile unsigned int *)ioremap(PWM_BASE, 1024); clk = (volatile unsigned int *)ioremap(CLOCK_BASE, 1024); // Set pin directions for the output INP_GPIO(GPIO_OUTP); OUT_GPIO(GPIO_OUTP); // PWM and clock settings SET_GPIO_ALT(GPIO_PWM1, GPIO_ALT); // stop clock and waiting for busy flag doesn't work, so kill clock *(clk + CLK_CTL) = CLK_PASSWD | CLK_CTL_KILL; udelay(10); // Set clock divider *(clk + CLK_DIV) = CLK_PASSWD | CLK_DIV_DIVI(96); // source=osc and enable clock *(clk + CLK_CTL) = CLK_PASSWD | CLK_CTL_ENAB | CLK_CTL_SRC(CLK_CTL_SRC_OSC); // disable PWM and start with a clean register *(pwm + PWM_CTL) = 0; // needs some time until the PWM module gets disabled, without the delay the PWM module crashes udelay(10); // Set the PWM range *(pwm + PWM_RNG2) = 4000; // Initialize with a 50% dutycycle setServo(50); // start PWM in M/S transmission mode *(pwm + PWM_CTL) = PWM_CTL_MSEN2 | PWM_CTL_PWEN2; interrupt_config(); return SUCCESS; }
static int initClock(int clock, int source, int divI, int divF, int MASH) { int ctl[] = {CLK_GP0_CTL, CLK_GP2_CTL}; int div[] = {CLK_GP0_DIV, CLK_GP2_DIV}; int src[CLK_SRCS] = {CLK_CTL_SRC_PLLD, CLK_CTL_SRC_OSC, CLK_CTL_SRC_HDMI, CLK_CTL_SRC_PLLC}; int clkCtl, clkDiv, clkSrc; uint32_t setting; if ((clock < 0) || (clock > 1)) return -1; if ((source < 0) || (source > 3 )) return -2; if ((divI < 2) || (divI > 4095)) return -3; if ((divF < 0) || (divF > 4095)) return -4; if ((MASH < 0) || (MASH > 3)) return -5; clkCtl = ctl[clock]; clkDiv = div[clock]; clkSrc = src[source]; clkReg[clkCtl] = CLK_PASSWD | CLK_CTL_KILL; /* wait for clock to stop */ while (clkReg[clkCtl] & CLK_CTL_BUSY) { usleep(10); } clkReg[clkDiv] = (CLK_PASSWD | CLK_DIV_DIVI(divI) | CLK_DIV_DIVF(divF)); usleep(10); clkReg[clkCtl] = (CLK_PASSWD | CLK_CTL_MASH(MASH) | CLK_CTL_SRC(clkSrc)); usleep(10); clkReg[clkCtl] |= (CLK_PASSWD | CLK_CTL_ENAB); }
int rpi_gpclk_setup(int chan, int source, int div_int, int div_frac) { int MASH = 0; uint32_t clksrc; if (!rpi_registers_mapping.mapping_initialized) return -1; if ((source < 0) || (source > sizeof(rpi_gpclk_src_to_reg) / sizeof(*rpi_gpclk_src_to_reg) )) return -2; if ((div_int < 2) || (div_int > 4095)) return -3; if ((div_frac < 0) || (div_frac > 4095)) return -4; if ((MASH < 0) || (MASH > 3)) return -5; clksrc = rpi_gpclk_src_to_reg[source]; CLK_GPx_CTL(chan) = CLK_PASSWD | CLK_CTL_KILL; while (CLK_GPx_CTL(chan) & CLK_CTL_BUSY){ usleep(10); } CLK_GPx_DIV(chan) = (CLK_PASSWD | CLK_DIV_DIVI(div_int) | CLK_DIV_DIVF(div_frac)); usleep(10); CLK_GPx_CTL(chan) = (CLK_PASSWD | CLK_CTL_MASH(MASH) | CLK_CTL_SRC(clksrc)); usleep(10); CLK_GPx_CTL(chan) |= (CLK_PASSWD | CLK_CTL_ENAB); return 0; }