2010-01-06 14:49:48 +03:00
/*
* TI CDCE949 clock synthesizer driver
*
* Note : This implementation assumes an input of 27 MHz to the CDCE .
* This is by no means constrained by CDCE hardware although the datasheet
* does use this as an example for all illustrations and more importantly :
* that is the crystal input on boards it is currently used on .
*
* Copyright ( C ) 2009 Texas Instruments Incorporated . http : //www.ti.com/
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/kernel.h>
# include <linux/clk.h>
# include <linux/platform_device.h>
# include <linux/i2c.h>
2011-08-01 00:14:14 +04:00
# include <linux/module.h>
2010-01-06 14:49:48 +03:00
# include <mach/clock.h>
2010-02-26 02:36:38 +03:00
# include <mach/cdce949.h>
2010-01-06 14:49:48 +03:00
# include "clock.h"
static struct i2c_client * cdce_i2c_client ;
2010-01-12 16:25:35 +03:00
static DEFINE_MUTEX ( cdce_mutex ) ;
2010-01-06 14:49:48 +03:00
/* CDCE register descriptor */
struct cdce_reg {
u8 addr ;
u8 val ;
} ;
/* Per-Output (Y1, Y2 etc.) frequency descriptor */
struct cdce_freq {
/* Frequency in KHz */
unsigned long frequency ;
/*
* List of registers to program to obtain a particular frequency .
* 0x0 in register address and value is the end of list marker .
*/
struct cdce_reg * reglist ;
} ;
# define CDCE_FREQ_TABLE_ENTRY(line, out) \
{ \
. reglist = cdce_y # # line # # _ # # out , \
. frequency = out , \
}
/* List of CDCE outputs */
struct cdce_output {
/* List of frequencies on this output */
struct cdce_freq * freq_table ;
/* Number of possible frequencies */
int size ;
} ;
/*
* Finding out the values to program into CDCE949 registers for a particular
* frequency output is not a simple calculation . Have a look at the datasheet
* for the details . There is desktop software available to help users with
* the calculations . Here , we just depend on the output of that software
* ( or hand calculations ) instead trying to runtime calculate the register
* values and inflicting misery on ourselves .
*/
static struct cdce_reg cdce_y1_148500 [ ] = {
{ 0x13 , 0x00 } ,
/* program PLL1_0 multiplier */
{ 0x18 , 0xaf } ,
{ 0x19 , 0x50 } ,
{ 0x1a , 0x02 } ,
{ 0x1b , 0xc9 } ,
/* program PLL1_11 multiplier */
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
{ 0x1e , 0x02 } ,
{ 0x1f , 0xc9 } ,
/* output state selection */
{ 0x15 , 0x00 } ,
{ 0x14 , 0xef } ,
/* switch MUX to PLL1 output */
{ 0x14 , 0x6f } ,
{ 0x16 , 0x06 } ,
/* set P2DIV divider, P3DIV and input crystal */
{ 0x17 , 0x06 } ,
{ 0x01 , 0x00 } ,
{ 0x05 , 0x48 } ,
{ 0x02 , 0x80 } ,
/* enable and disable PLL */
{ 0x02 , 0xbc } ,
{ 0x03 , 0x01 } ,
{ } ,
} ;
static struct cdce_reg cdce_y1_74250 [ ] = {
{ 0x13 , 0x00 } ,
{ 0x18 , 0xaf } ,
{ 0x19 , 0x50 } ,
{ 0x1a , 0x02 } ,
{ 0x1b , 0xc9 } ,
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
{ 0x1e , 0x02 } ,
{ 0x1f , 0xc9 } ,
/* output state selection */
{ 0x15 , 0x00 } ,
{ 0x14 , 0xef } ,
/* switch MUX to PLL1 output */
{ 0x14 , 0x6f } ,
{ 0x16 , 0x06 } ,
/* set P2DIV divider, P3DIV and input crystal */
{ 0x17 , 0x06 } ,
{ 0x01 , 0x00 } ,
{ 0x05 , 0x48 } ,
{ 0x02 , 0x80 } ,
/* enable and disable PLL */
{ 0x02 , 0xbc } ,
{ 0x03 , 0x02 } ,
{ } ,
} ;
static struct cdce_reg cdce_y1_27000 [ ] = {
{ 0x13 , 0x00 } ,
{ 0x18 , 0x00 } ,
{ 0x19 , 0x40 } ,
{ 0x1a , 0x02 } ,
{ 0x1b , 0x08 } ,
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
{ 0x1e , 0x02 } ,
{ 0x1f , 0x08 } ,
{ 0x15 , 0x02 } ,
{ 0x14 , 0xed } ,
{ 0x16 , 0x01 } ,
{ 0x17 , 0x01 } ,
{ 0x01 , 0x00 } ,
{ 0x05 , 0x50 } ,
{ 0x02 , 0xb4 } ,
{ 0x03 , 0x01 } ,
{ } ,
} ;
static struct cdce_freq cdce_y1_freqs [ ] = {
CDCE_FREQ_TABLE_ENTRY ( 1 , 148500 ) ,
CDCE_FREQ_TABLE_ENTRY ( 1 , 74250 ) ,
CDCE_FREQ_TABLE_ENTRY ( 1 , 27000 ) ,
} ;
static struct cdce_reg cdce_y5_13500 [ ] = {
{ 0x27 , 0x08 } ,
{ 0x28 , 0x00 } ,
{ 0x29 , 0x40 } ,
{ 0x2a , 0x02 } ,
{ 0x2b , 0x08 } ,
{ 0x24 , 0x6f } ,
{ } ,
} ;
static struct cdce_reg cdce_y5_16875 [ ] = {
{ 0x27 , 0x08 } ,
{ 0x28 , 0x9f } ,
{ 0x29 , 0xb0 } ,
{ 0x2a , 0x02 } ,
{ 0x2b , 0x89 } ,
{ 0x24 , 0x6f } ,
{ } ,
} ;
static struct cdce_reg cdce_y5_27000 [ ] = {
{ 0x27 , 0x04 } ,
{ 0x28 , 0x00 } ,
{ 0x29 , 0x40 } ,
{ 0x2a , 0x02 } ,
{ 0x2b , 0x08 } ,
{ 0x24 , 0x6f } ,
{ } ,
} ;
static struct cdce_reg cdce_y5_54000 [ ] = {
{ 0x27 , 0x04 } ,
{ 0x28 , 0xff } ,
{ 0x29 , 0x80 } ,
{ 0x2a , 0x02 } ,
{ 0x2b , 0x07 } ,
{ 0x24 , 0x6f } ,
{ } ,
} ;
static struct cdce_reg cdce_y5_81000 [ ] = {
{ 0x27 , 0x02 } ,
{ 0x28 , 0xbf } ,
{ 0x29 , 0xa0 } ,
{ 0x2a , 0x03 } ,
{ 0x2b , 0x0a } ,
{ 0x24 , 0x6f } ,
{ } ,
} ;
static struct cdce_freq cdce_y5_freqs [ ] = {
CDCE_FREQ_TABLE_ENTRY ( 5 , 13500 ) ,
CDCE_FREQ_TABLE_ENTRY ( 5 , 16875 ) ,
CDCE_FREQ_TABLE_ENTRY ( 5 , 27000 ) ,
CDCE_FREQ_TABLE_ENTRY ( 5 , 54000 ) ,
CDCE_FREQ_TABLE_ENTRY ( 5 , 81000 ) ,
} ;
static struct cdce_output output_list [ ] = {
[ 1 ] = { cdce_y1_freqs , ARRAY_SIZE ( cdce_y1_freqs ) } ,
[ 5 ] = { cdce_y5_freqs , ARRAY_SIZE ( cdce_y5_freqs ) } ,
} ;
int cdce_set_rate ( struct clk * clk , unsigned long rate )
{
int i , ret = 0 ;
struct cdce_freq * freq_table = output_list [ clk - > lpsc ] . freq_table ;
struct cdce_reg * regs = NULL ;
if ( ! cdce_i2c_client )
return - ENODEV ;
if ( ! freq_table )
return - EINVAL ;
for ( i = 0 ; i < output_list [ clk - > lpsc ] . size ; i + + ) {
if ( freq_table [ i ] . frequency = = rate / 1000 ) {
regs = freq_table [ i ] . reglist ;
break ;
}
}
if ( ! regs )
return - EINVAL ;
2010-01-12 16:25:35 +03:00
mutex_lock ( & cdce_mutex ) ;
2010-01-06 14:49:48 +03:00
for ( i = 0 ; regs [ i ] . addr ; i + + ) {
ret = i2c_smbus_write_byte_data ( cdce_i2c_client ,
regs [ i ] . addr | 0x80 , regs [ i ] . val ) ;
if ( ret )
2010-01-12 16:25:35 +03:00
break ;
2010-01-06 14:49:48 +03:00
}
2010-01-12 16:25:35 +03:00
mutex_unlock ( & cdce_mutex ) ;
2010-01-06 14:49:48 +03:00
2010-01-12 16:25:35 +03:00
if ( ! ret )
clk - > rate = rate ;
2010-01-06 14:49:48 +03:00
2010-01-12 16:25:35 +03:00
return ret ;
2010-01-06 14:49:48 +03:00
}
static int cdce_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
cdce_i2c_client = client ;
return 0 ;
}
2012-12-22 02:02:24 +04:00
static int cdce_remove ( struct i2c_client * client )
2010-01-06 14:49:48 +03:00
{
cdce_i2c_client = NULL ;
return 0 ;
}
static const struct i2c_device_id cdce_id [ ] = {
{ " cdce949 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , cdce_id ) ;
static struct i2c_driver cdce_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = " cdce949 " ,
} ,
. probe = cdce_probe ,
2012-12-22 02:02:24 +04:00
. remove = cdce_remove ,
2010-01-06 14:49:48 +03:00
. id_table = cdce_id ,
} ;
static int __init cdce_init ( void )
{
return i2c_add_driver ( & cdce_driver ) ;
}
subsys_initcall ( cdce_init ) ;
static void __exit cdce_exit ( void )
{
i2c_del_driver ( & cdce_driver ) ;
}
module_exit ( cdce_exit ) ;
MODULE_AUTHOR ( " Texas Instruments " ) ;
MODULE_DESCRIPTION ( " CDCE949 clock synthesizer driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;