Add codec wm8994

This commit is contained in:
root
2010-07-14 10:52:16 +08:00
parent 5d8d8603d6
commit 4aa53c4a71
10 changed files with 3749 additions and 5 deletions

View File

@@ -341,7 +341,21 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
.platform_data=&rk2818_pca9554_data.gpio_base,
},
#endif
{}
#if defined (CONFIG_SND_SOC_WM8994)
{
.type = "wm8994",
.addr = 0x1a,
.flags = 0,
},
#endif
#if defined (CONFIG_PMIC_LP8725)
{
.type = "lp8725",
.addr = 0x79,
.flags = 0,
},
#endif
{},
};

View File

@@ -115,4 +115,10 @@ config BATTERY_RK2818
depends on RK28_ADC
help
Say Y to enable support for the battery on the RK2818.
config PMIC_LP8725
tristate "pmic lp8725"
depends on I2C
help
Say Y to enable support for the pmic lp8725 on the RK2818.
endif # POWER_SUPPLY

View File

@@ -30,3 +30,4 @@ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_RK2818) += rk2818_battery.o
obj-$(CONFIG_PMIC_LP8725) += pmic_lp8725.o

780
drivers/power/pmic_lp8725.c Normal file
View File

@@ -0,0 +1,780 @@
/* arch/arm/mach-rk2818/example.c
*
* Copyright (C) 2010 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*******************************************************************/
/* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED. */
/*******************************************************************
FILE : PCA9554.C
DESC : <20><>չGPIO <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>س<EFBFBD><D8B3><EFBFBD>
AUTHOR : ZHONGYW
DATE : 2009-4-26
NOTES :
$LOG: GPIO.C,V $
REVISION 0.01
********************************************************************/
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <asm/mach-types.h>
#include <linux/irq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/rk2818_iomap.h>
#include <mach/iomux.h>
#include <linux/device.h>
#include <mach/gpio.h>
#include <asm/gpio.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <mach/board.h>
#include <linux/delay.h>
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
#if 1
#define DBGERR(x...) printk(KERN_INFO x)
#else
#define DBGERR(x...)
#endif
#define DEFSEL_VIN1
#define GENERAL_REG_ADDR 0x0
#define LDO1_REG_ADDR 0x01
#define LDO2_REG_ADDR 0x02
#define LDO3_REG_ADDR 0x03
#define LDO4_REG_ADDR 0x04
#define LDO5_REG_ADDR 0x05
#define LILO1_REG_ADDR 0x06
#define LILO2_REG_ADDR 0x07
#define BUCK1_V1_REG_ADDR 0x08
#define BUCK1_V2_REG_ADDR 0x09
#define BUCK2_V1_REG_ADDR 0x0a
#define BUCK2_V2_REG_ADDR 0x0b
#define BUCK_CTR_REG_ADDR 0x0c
#define LDO_CTR_REG_ADDR 0x0d
#define PULLDOWN_REG_ADDR 0x0e
#define STATUS_REG_ADDR 0x0f
#define LP8725_LDO_NUM 5
#define LP8725_LILO_NUM 2
#define LP8725_BUCK_NUM 2
#define LDO_BUCKV1_TIME 5 //<2F><>3
#define LDO_BUCKV_V 0 //<2F><>5
#define BUCKV2_CL_BIT 6 //<2F><>2
#ifdef DEFSEL_VIN1
#define GENERAL_REG_DEFAULT 0x59 //0101 1001 buck1output dependon dvs pin, dvs=1 v1 is used buck2v1 is output
#define LDO1_REG_T_DEFAULT 0x02 //1001 1001
#define LDO1_REG_V_DEFAULT 0x19
#define LDO2_REG_T_DEFAULT 0x04 //1001 1001
#define LDO2_REG_V_DEFAULT 0x19
#define LDO3_REG_T_DEFAULT 0x05 // 1011 1111
#define LDO3_REG_V_DEFAULT 0x1f
#define LDO4_REG_T_DEFAULT 0x04 // 1001 1101
#define LDO4_REG_V_DEFAULT 0x1d
#define LDO5_REG_T_DEFAULT 0x04 //1000 1100
#define LDO5_REG_V_DEFAULT 0x0c
#define LILO1_REG_T_DEFAULT 0x05 //1010 1000
#define LILO1_REG_V_DEFAULT 0x08
#define LILO2_REG_T_DEFAULT 0x02 // 0101 0000
#define LILO2_REG_V_DEFAULT 0x10
#define BUCK1_V1_REG_T_DEFAULT 0x00 // 0000 0100
#define BUCK1_V1_REG_V_DEFAULT 0x04
#define BUCK1_V2_REG_C_DEFAULT 0x03 //1100 1000 <20>߶<EFBFBD>
#define BUCK1_V2_REG_V_DEFAULT 0x08
#define BUCK2_V1_REG_T_DEFAULT 0x02 // 0101 0001
#define BUCK2_V1_REG_V_DEFAULT 0x11
#define BUCK2_V2_REG_C_DEFAULT 0x02//1001 0001 <20>߶<EFBFBD>
#define BUCK2_V2_REG_V_DEFAULT 0x11// <20><>5
#define BUCK2_CTR_REG_ADDR 0x11 // 0001 0001
#define LDO_CTR_REG_DEFAULT 0x7f //0111 1111
#define PULLDOWN_DEFAULT 0x7f //0111 1111
#define STATUS_REG_DEFAULT 0x00 //0000 0000
#else
#define GENERAL_REG_DEFAULT 0x59 //0101 1001
#define LDO1_REG_T_DEFAULT 0x01 // 0011 0101
#define LDO1_REG_V_DEFAULT 0x15
#define LDO2_REG_T_DEFAULT 0x01 // 0011 1001
#define LDO2_REG_V_DEFAULT 0x19
#define LDO3_REG_T_DEFAULT 0x02 // 0101 1001
#define LDO3_REG_V_DEFAULT 0x19
#define LDO4_REG_T_DEFAULT 0x02 // 0101 1001
#define LDO4_REG_V_DEFAULT 0x19
#define LDO5_REG_T_DEFAULT 0x01 // 0011 1001
#define LDO5_REG_V_DEFAULT 0x19
#define LILO1_REG_T_DEFAULT 0x01 //0011 1111
#define LILO1_REG_V_DEFAULT 0x1f
#define LILO2_REG_T_DEFAULT 0x00 // 0000 1000
#define LILO2_REG_V_DEFAULT 0x08
#define BUCK1_V1_REG_T_DEFAULT 0x00 // 0000 1000
#define BUCK1_V1_REG_V_DEFAULT 0x08
#define BUCK1_V2_REG_C_DEFAULT 0x03 //1100 0100 <20>߶<EFBFBD>
#define BUCK1_V2_REG_V_DEFAULT 0x04
#define BUCK2_V1_REG_T_DEFAULT 0x01 // 0011 0001
#define BUCK2_V1_REG_V_DEFAULT 0x11
#define BUCK2_V2_REG_C_DEFAULT 0x02 //1001 0001 <20>߶<EFBFBD>
#define BUCK2_V2_REG_V_DEFAULT 0x11// <20><>5
#define BUCK_CTR_REG_ADDR 0x11 // 0001 0001
#define LDO_CTR_REG_DEFAULT 0x7f //0111 1111
#define PULLDOWN_REG_DEFAULT 0x7f //0111 1111
#define STATUS_REG_DEFAULT 0x00 //0000 0000
#endif
struct i2c_client *lp8725_client;
#define lp8725getbit(a,num) (((a)>>(num))&0x01)
#define lp8725setbit(a,num) ((a)|(0x01<<(num)))
#define lp8725clearbit(a,num) ((a)&(~(0x01<<(num))))
static const struct i2c_device_id lp8725_id[] =
{
{ "lp8725", 0, },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp8725_id);
struct lp8725_regs_s
{
uint8_t general_reg_val;
uint8_t ldo_reg_val[5];
uint8_t lilo_reg_val[2];
uint8_t buck_v1_reg_val[2];
uint8_t buck_v2_reg_val[2];
uint8_t buck_ctr_reg_val;
uint8_t ldo_ctr_reg_val;
uint8_t pulldown_reg_val;
uint8_t status_reg_val;
};
struct lp8725_vol_range_s
{
uint16_t vol_low;
uint16_t vol_high;
uint16_t rang;
};
static struct lp8725_regs_s lp8725_regs;
uint8_t ldo_reg_t_default[LP8725_LDO_NUM]={LDO1_REG_T_DEFAULT,LDO2_REG_T_DEFAULT,LDO3_REG_T_DEFAULT,LDO4_REG_T_DEFAULT,LDO5_REG_T_DEFAULT};
uint8_t ldo_reg_v_default[LP8725_LDO_NUM]={LDO1_REG_V_DEFAULT,LDO2_REG_V_DEFAULT,LDO3_REG_V_DEFAULT,LDO4_REG_V_DEFAULT,LDO5_REG_V_DEFAULT};
uint8_t lilo_reg_t_default[LP8725_LILO_NUM]={LILO1_REG_T_DEFAULT,LILO2_REG_T_DEFAULT};
uint8_t lilo_reg_v_default[LP8725_LILO_NUM]={LILO1_REG_V_DEFAULT,LILO2_REG_V_DEFAULT};
uint8_t buck_v1_reg_t_default[LP8725_BUCK_NUM]={BUCK1_V1_REG_T_DEFAULT,BUCK2_V1_REG_T_DEFAULT};
uint8_t buck_v1_reg_v_default[LP8725_BUCK_NUM]={BUCK1_V1_REG_V_DEFAULT,BUCK2_V1_REG_V_DEFAULT};
uint8_t buck_v2_reg_c_default[LP8725_BUCK_NUM]={BUCK1_V2_REG_C_DEFAULT,BUCK2_V2_REG_C_DEFAULT};
uint8_t buck_v2_reg_v_default[LP8725_BUCK_NUM]={BUCK1_V2_REG_V_DEFAULT,BUCK2_V2_REG_V_DEFAULT};
#define LDO_RANG 5
#define LILO_RANG 5
#define BULK_RANG 6
struct lp8725_vol_range_s ldo_vol_range[LDO_RANG]={{120,190,5},{190,260,10},{260,300,5},{300,310,10},{310,330,20}};
struct lp8725_vol_range_s lilo_vol_range[LILO_RANG]={{80,140,5},{140,280,10},{280,290,5},{290,310,10},{310,330,20}};
struct lp8725_vol_range_s buck_vol_range[BULK_RANG]={{80,140,5},{140,170,10},{170,190,5},{190,280,10},{280,290,5},{290,300,10}};
/* **********************************************************************
* д<>Ĵ<EFBFBD><C4B4><EFBFBD>
* return <0 failed
* * ***********************************************************************/
static int lp8725_write_reg(struct i2c_client *client, uint8_t reg, uint8_t val)
{
int ret=-1;
DBG("**run in %s**\n",__FUNCTION__);
struct i2c_adapter *adap;
struct i2c_msg msg;
char tx_buf[2];
if(!client)
return ret;
adap = client->adapter;
tx_buf[0] = reg;
tx_buf[1]=val;
//DBG("**run in %s**\n",__FUNCTION__);
msg.addr = client->addr;
msg.buf = &tx_buf[0];
msg.len = 1 +1;
msg.flags = client->flags;
msg.scl_rate = 200*1000;
//DBG("**run in %s**\n",__FUNCTION__);
ret = i2c_transfer(adap, &msg, 1);
//DBG("**run in %s**\n",__FUNCTION__);
return ret;
DBG("**run out %s**\n",__FUNCTION__);
}
/* **********************************************************************
* <20><><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
* return <0 failed
* * ***********************************************************************/
#if 1
static int lp8725_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *val)
{
int ret;
struct i2c_adapter *adap;
struct i2c_msg msgs[2];
if(!client)
return ret;
adap = client->adapter;
//<2F><><EFBFBD>ͼĴ<CDBC><C4B4><EFBFBD><EFBFBD><EFBFBD>ַ
msgs[0].addr = client->addr;
msgs[0].buf = &reg;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].scl_rate = 200*1000;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//msgs[1].buf = val;
DBG("msgs[1].buf = %d\n",*msgs[1].buf);
//msgs[1].buf = val;
msgs[1].buf = val;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = 1;
msgs[1].scl_rate = 200*1000;
ret = i2c_transfer(adap, msgs, 2);
//DBG("**has run at %s %d ret=%d**\n",__FUNCTION__,__LINE__,ret);
DBG("msgs[1].buf = %d\n",*(msgs[1].buf));
return ret;
}
#else
static int lp8725_read_reg(struct i2c_client *client, uint8_t reg)
{
int ret;
struct i2c_adapter *adap;
struct i2c_msg msgs[2];
if(!client)
return ret;
adap = client->adapter;
//<2F><><EFBFBD>ͼĴ<CDBC><C4B4><EFBFBD><EFBFBD><EFBFBD>ַ
msgs[0].addr = client->addr;
msgs[0].buf = &reg;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].scl_rate = 200*1000;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
msgs[1].buf;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = 1;
msgs[1].scl_rate = 200*1000;
ret = i2c_transfer(adap, msgs, 2);
//DBG("**has run at %s %d ret=%d**\n",__FUNCTION__,__LINE__,ret);
DBG("msgs[1].buf = %d\n",*msgs[1].buf);
return ret;
}
#endif
/* **********************************************************************
* <20><><EFBFBD><EFBFBD>ldo<64><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ
*ldon:ldo<64><6F><EFBFBD><EFBFBD> <20><>ldo1 ldon=1<><31>vol <20><>ѹ<EFBFBD><D1B9>λ10mv <20><>1.2v vol=120
*<2A><>ѹ<EFBFBD><D1B9>Χ:<3A><>1.2v<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>0.05v
* return <0 failed
* * ***********************************************************************/
int lp8725_set_ldo_vol(uint8_t ldon,uint16_t vol)
{
uint8_t val=0;
uint8_t reg_val=0;
int i;
if((vol>ldo_vol_range[LDO_RANG-1].vol_high)||(vol<ldo_vol_range[0].vol_low)||ldon>LP8725_LDO_NUM)
return -1;
for(i=0;i<LDO_RANG;i++)
{
if(vol<=ldo_vol_range[i].vol_high)
{
val+=(vol-ldo_vol_range[i].vol_low)/ldo_vol_range[i].rang;
break;
}
else
val+=(ldo_vol_range[i].vol_high-ldo_vol_range[i].vol_low)/ldo_vol_range[i].rang;
DBG("val=0x%x,vol=%d\n",val,vol);
}
DBG("val=0x%x,vol=%d\n",val,vol);
reg_val=(ldo_reg_t_default[ldon-1]<<LDO_BUCKV1_TIME)|val;
DBG("ldo_reg_t_default[ldon-1]=0x%x,LDO_BUCKV1_TIME=0x%x\n",ldo_reg_t_default[ldon-1],LDO_BUCKV1_TIME);
DBG("ldo_reg_t_default[ldon-1]<<LDO_BUCKV1_TIME=0x%x\n",ldo_reg_t_default[ldon-1]<<LDO_BUCKV1_TIME);
DBG("ADDR=0x%x,reg_val=0x%x\n",LDO1_REG_ADDR+ldon-1,reg_val);
if(lp8725_write_reg(lp8725_client,LDO1_REG_ADDR+ldon-1,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.ldo_reg_val[ldon-1]=reg_val;
return 0;
}
/* **********************************************************************
* <20><><EFBFBD><EFBFBD>lilo<6C><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ
*ldon:ldo<64><6F><EFBFBD><EFBFBD> <20><>lilo1 lilon=1<><31>vol <20><>ѹ<EFBFBD><D1B9>λ10mv <20><>0.8v vol=80
*<2A><>ѹ<EFBFBD><D1B9>Χ:<3A><>ѹ<EFBFBD><D1B9>[0.8,1.4]ʱ<><CAB1><EFBFBD><EFBFBD>0.05v<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>[1.4,3.3]ʱ<><CAB1><EFBFBD><EFBFBD>0.1v
* return <0 failed
* * ***********************************************************************/
int lp8725_set_lilo_vol(uint8_t lilon,uint16_t vol)
{
uint8_t val=0;
uint8_t reg_val=0;
int i;
if((vol>lilo_vol_range[LILO_RANG-1].vol_high)||(vol<lilo_vol_range[0].vol_low)||lilon>LP8725_LILO_NUM)
return -1;
for(i=0;i<LILO_RANG;i++)
{
if(vol<=lilo_vol_range[i].vol_high)
{
val+=(vol-lilo_vol_range[i].vol_low)/lilo_vol_range[i].rang;
break;
}
else
val+=(lilo_vol_range[i].vol_high-lilo_vol_range[i].vol_low)/lilo_vol_range[i].rang;
}
reg_val=(lilo_reg_t_default[lilon-1]<<LDO_BUCKV1_TIME)|val;
if(lp8725_write_reg(lp8725_client,LILO1_REG_ADDR+lilon-1,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.lilo_reg_val[lilon-1]=reg_val;
return 0;
}
/* **********************************************************************
* <20><><EFBFBD><EFBFBD>buck<63><6B>v1 v2 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD>
*ldon:ldo<64><6F><EFBFBD><EFBFBD> <20><>buck1 buckn=1<><31>vol <20><>ѹ<EFBFBD><D1B9>λ10mv <20><>0.8v vol=80 <20><>v2=1 <20><><EFBFBD><EFBFBD>ѹֵд<D6B5><D0B4>v2 reg<65><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>v1 reg
*<2A><>ѹ<EFBFBD><D1B9>Χ:<3A><>ѹ<EFBFBD><D1B9>[0.8,1.4]ʱ<><CAB1><EFBFBD><EFBFBD>0.05v<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>[1.4,1.7]ʱ<><CAB1><EFBFBD><EFBFBD>0.1v<EFBFBD><EFBFBD>
*<2A><>ѹ<EFBFBD><D1B9>[1.7,1.9]ʱ<><CAB1><EFBFBD><EFBFBD>0.05v<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>[1.9,3.0]ʱ<><CAB1><EFBFBD><EFBFBD>0.1v
* return <0 failed
* * ***********************************************************************/
static int lp8725_set_buck_vol_v1orv2(uint8_t buckn,uint16_t vol,uint8_t v2)
{
uint8_t val=0;
uint8_t reg_val=0;
uint8_t reg_addr=0;
int i;
if(vol>buck_vol_range[BULK_RANG-1].vol_high||vol<buck_vol_range[0].vol_low||buckn>LP8725_BUCK_NUM)
return -1;
for(i=0;i<BULK_RANG;i++)
{
if(vol<=buck_vol_range[i].vol_high)
{
val+=(vol-buck_vol_range[i].vol_low)/buck_vol_range[i].rang;
break;
}
else
val+=(buck_vol_range[i].vol_high-buck_vol_range[i].vol_low)/buck_vol_range[i].rang;
}
reg_addr=BUCK1_V1_REG_ADDR+(buckn-1)*2;
reg_val=(buck_v1_reg_t_default[buckn-1]<<LDO_BUCKV1_TIME)|val;
if(v2)
reg_addr=BUCK1_V2_REG_ADDR+(buckn-1)*2;
if(lp8725_write_reg(lp8725_client,reg_addr,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
if(v2)
lp8725_regs.buck_v2_reg_val[buckn-1]=reg_val;
else
lp8725_regs.buck_v1_reg_val[buckn-1]=reg_val;
return 0;
}
/***************************************************************
*
*
****************************************************************/
int lp8725_set_buck_dvsn_v_bit(uint8_t buckn,uint8_t dvs)
{
uint8_t reg_val=0;
if(dvs)
reg_val=lp8725_regs.general_reg_val|(0x01<<(2+buckn-1));
else
reg_val=lp8725_regs.general_reg_val&(~0x01<<(12+buckn-1));
if(lp8725_write_reg(lp8725_client,GENERAL_REG_ADDR,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.general_reg_val=reg_val;
return 0;
}
/* **********************************************************************
* <20><><EFBFBD><EFBFBD>buck<63><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ
*ldon:ldo<64><6F><EFBFBD><EFBFBD> <20><>buck1 buckn=1<><31>vol <20><>ѹ<EFBFBD><D1B9>λ10mv <20><>0.8v vol=80
*<2A><>ѹ<EFBFBD><D1B9>Χ:<3A><>ѹ<EFBFBD><D1B9>[0.8,1.4]ʱ<><CAB1><EFBFBD><EFBFBD>0.05v<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>[1.4,1.7]ʱ<><CAB1><EFBFBD><EFBFBD>0.1v<EFBFBD><EFBFBD>
*<2A><>ѹ<EFBFBD><D1B9>[1.7,1.9]ʱ<><CAB1><EFBFBD><EFBFBD>0.05v<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>[1.9,3.0]ʱ<><CAB1><EFBFBD><EFBFBD>0.1v
*ÿ<><C3BF>buck <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>v1<76><31>v2<76><32>buck <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*ѡ<><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǹ<EFBFBD><C7B8>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ
* buck1: dvs1_v=1 output vol depend on buck1_v1 reg,else depend on dvs pin. dvspin=1 output vol depend on buck1_v1,esle output vol depend on buck1_v2
*buck2:dvs1_v=1 output vol depend on buck2_v1 reg,else depend on buck2_v2.
* return <0 failed
* * ***********************************************************************/
int lp8725_set_buck_vol(uint8_t buckn,uint16_t vol)
{
if(lp8725_set_buck_vol_v1orv2(buckn,vol,0)<0)
return -1;
return lp8725_set_buck_vol_v1orv2(buckn,vol,1);
}
int get_dvs_pin_level(void)
{
// dvs pin is low return 0
}
int set_dvs_pin_level(uint8_t level)
{
}
/*******************************************************************************
*in sleep mode all pins val is low
*reg SLEEP_MODE=0,and pin DVS=0<><30>this ic enter into seelp mode
********************************************************************************/
int lp8725_setinto_sleep(uint8_t sleep)
{
uint8_t reg_val=0;
set_dvs_pin_level(0);
if(sleep)
reg_val=lp8725_regs.general_reg_val|(0x01<<1);
else
reg_val=lp8725_regs.general_reg_val&(~0x01<<1);
if(lp8725_write_reg(lp8725_client,GENERAL_REG_ADDR,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.general_reg_val=reg_val;
return 0;
}
/***************************************************************
*
*
****************************************************************/
int lp8725_buck_en(uint8_t buckn,uint8_t enble)
{
uint8_t reg_val=0;
if(buckn==1)
{
if(enble)
reg_val=lp8725_regs.general_reg_val|0x01;
else
reg_val=lp8725_regs.general_reg_val&(~0x01);
}
if(buckn==2)
{
if(enble)
reg_val=lp8725_regs.general_reg_val|(0x01<<4);
else
reg_val=lp8725_regs.general_reg_val&(~0x01<<4);
}
if(lp8725_write_reg(lp8725_client,GENERAL_REG_ADDR,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.general_reg_val=reg_val;
return 0;
}
int lp8725_lilo_en(uint8_t lilon,uint8_t enble)
{
uint8_t reg_val=0;
if(enble)
reg_val=lp8725_regs.ldo_ctr_reg_val|(0x01<<(5+lilon-1));
else
reg_val=lp8725_regs.ldo_ctr_reg_val&(~(0x01<<(5+lilon-1)));
if(lp8725_write_reg(lp8725_client,LDO_CTR_REG_ADDR,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.ldo_ctr_reg_val=reg_val;
return 0;
}
/***************************************************************
*ldo3 is enbale if pin LdO3_EN=1 or LDO3 enable reg=1
*
****************************************************************/
int lp8725_ldo_en(uint8_t ldo,uint8_t enble)
{
uint8_t reg_val=0;
if(enble)
reg_val=lp8725_regs.ldo_ctr_reg_val|(0x01<<(ldo-1));
else
reg_val=lp8725_regs.ldo_ctr_reg_val&(~(0x01<<(ldo-1)));
if(lp8725_write_reg(lp8725_client,LDO_CTR_REG_ADDR,reg_val)<0)
{
DBGERR("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
lp8725_regs.ldo_ctr_reg_val=reg_val;
return 0;
}
void lp8725_set_init(void)
{
uint8_t reg_val=0;
uint8_t read_ret;
lp8725_regs.general_reg_val=GENERAL_REG_DEFAULT;
lp8725_regs.buck_ctr_reg_val=BUCK_CTR_REG_ADDR;
lp8725_regs.pulldown_reg_val=PULLDOWN_REG_ADDR;
lp8725_regs.status_reg_val=STATUS_REG_ADDR;
/*
<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ldo 1<><31>2<EFBFBD><32>5 lilo2Ĭ<32><C4AC>Ϊ<EFBFBD>ر<EFBFBD>
*/
DBG("**run in %s**\n",__FUNCTION__);
//reg_val=LDO_CTR_REG_ADDR&&(~(1<<0))&&(~(1<<0))&&(~(1<<1))&&(~(1<<4))&&(~(1<<6));
reg_val=0x7f;
DBG("**lp8725_client=%s**LDO_CTR_REG_ADDR=%d**reg_val=%d\n",lp8725_client,LDO_CTR_REG_ADDR,reg_val);
if(lp8725_write_reg(lp8725_client,LDO_CTR_REG_ADDR,reg_val)<0)
{
DBG("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
/*
**set ldo4 VCCA 3.3V;ldo5 AVDD18 1.8v
*/
lp8725_set_ldo_vol(4,330);
lp8725_set_ldo_vol(5,180);
#if 0
DBG("**begin lp8725_read_reg %s %d \n",__FUNCTION__,__LINE__);
if(lp8725_read_reg(lp8725_client,0x00,&read_ret)<0)
{
DBG("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
DBG("**lp8725_read_reg %s %d return read_ret = %d\n",__FUNCTION__,__LINE__,read_ret);
#endif
lp8725_regs.ldo_ctr_reg_val=reg_val;
DBG("**run out %s**\n",__FUNCTION__);
}
#if 0
static __init int seqgen1_init(void)
{
uint8_t *read_val;
//uint8_t reg_val=0x98;
DBG("**************run in %s\n",__FUNCTION__);
//lp8725_set_ldo_vol(2,150);
//lp8725_set_lilo_vol(2,150);
//lp8725_set_buck_vol(2,170);
while(1)
{
DBG("\n***lp8725_lilo_en(2,0)\n");
lp8725_lilo_en(2,0);
mdelay(6000);
DBG("\n***lp8725_lilo_en(2,1)\n");
lp8725_lilo_en(2,1);
mdelay(6000);
}
#if 0
while(1)
{
int i;
for(i=180;i<=330;i=i-10)
{
DBG("\n\n**i=%d\n",i);
DBG("**************run in %s\n",__FUNCTION__);
lp8725_set_buck_vol(2,i);
mdelay(3000);
}
}
DBG("**************run out %s\n",__FUNCTION__);
if(lp8725_write_reg(lp8725_client,LDO2_REG_ADDR,reg_val)<0)
{
DBG("%s %d error\n",__FUNCTION__,__LINE__);
return -1;
}
while(1)
{
lp8725_read_reg(lp8725_client,LDO_CTR_REG_ADDR,read_val);
DBG("\n*****read_val = %d\n",read_val);
}
DBG("**************run out %s\n",__FUNCTION__);
#endif
return 0;
}
late_initcall(seqgen1_init);
#endif
static int __devinit lp8725_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret;
DBG("**%s in %d line,dev adr is %x**\n",__FUNCTION__,__LINE__,client->addr);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -EIO;
lp8725_client=client;
lp8725_set_init();
DBG("**run out %s**\n",__FUNCTION__);
return 0;
}
static int lp8725_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver lp8725_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "lp8725",
},
.probe = lp8725_probe,
.remove = lp8725_remove,
.id_table = lp8725_id,
};
static int __init lp8725_init(void)
{
int ret;
ret = i2c_add_driver(&lp8725_driver);
DBG("**lp8725_init return %d**\n",ret);
return ret;
}
static void __exit lp8725_exit(void)
{
i2c_del_driver(&lp8725_driver);
}
module_init(lp8725_init);
module_exit(lp8725_exit);
MODULE_AUTHOR(" XXX XXX@rock-chips.com");
MODULE_DESCRIPTION("Driver for rk2818 extend gpio device");
MODULE_LICENSE("GPL");

View File

@@ -51,6 +51,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
select SND_SOC_WM8993 if I2C
select SND_SOC_WM8994 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM9081 if I2C
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
@@ -205,6 +206,9 @@ config SND_SOC_WM8990
config SND_SOC_WM8993
tristate
config SND_SOC_WM8994
tristate
config SND_SOC_WM9081
tristate

View File

@@ -39,6 +39,7 @@ snd-soc-wm8974-objs := wm8974.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
snd-soc-wm8993-objs := wm8993.o
snd-soc-wm8994-objs := wm8994.o
snd-soc-wm9081-objs := wm9081.o
snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
@@ -89,6 +90,7 @@ obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o

2691
sound/soc/codecs/wm8994.c Executable file

File diff suppressed because it is too large Load Diff

60
sound/soc/codecs/wm8994.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on WM8753.h
*
* 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.
*
*/
#ifndef _WM8994_H
#define _WM8994_H
/* WM8994 register space */
#define WM8994_LINVOL 0x0f
#define WM8994_RINVOL 0x01
#define WM8994_LOUT1V 0x02
#define WM8994_ROUT1V 0x03
#define WM8994_ADCDAC 0x05
#define WM8994_IFACE 0x07
#define WM8994_SRATE 0x08
#define WM8994_LDAC 0x0a
#define WM8994_RDAC 0x0b
#define WM8994_BASS 0x0c
#define WM8994_TREBLE 0x0d
#define WM8994_RESET 0x00
#define WM8994_3D 0x10
#define WM8994_ALC1 0x11
#define WM8994_ALC2 0x12
#define WM8994_ALC3 0x13
#define WM8994_NGATE 0x14
#define WM8994_LADC 0x15
#define WM8994_RADC 0x16
#define WM8994_ADCTL1 0x17
#define WM8994_ADCTL2 0x18
#define WM8994_PWR1 0x19
#define WM8994_PWR2 0x1a
#define WM8994_ADCTL3 0x1b
#define WM8994_ADCIN 0x1f
#define WM8994_LADCIN 0x20
#define WM8994_RADCIN 0x21
#define WM8994_LOUTM1 0x22
#define WM8994_LOUTM2 0x23
#define WM8994_ROUTM1 0x24
#define WM8994_ROUTM2 0x25
#define WM8994_LOUT2V 0x28
#define WM8994_ROUT2V 0x29
#define WM8994_LPPB 0x43
#define WM8994_NUM_REG 0x44
#define WM8994_SYSCLK 0
extern struct snd_soc_dai wm8994_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8994;
#endif

View File

@@ -39,10 +39,10 @@ config SND_ROCKCHIP_SOC_RK1000
if SND_ROCKCHIP_SOC_WM8988 || SND_ROCKCHIP_SOC_RK1000 || SND_ROCKCHIP_SOC_WM8994
choice
prompt "set i2s type"
config SND_ROCKCHIP_SOC_SLAVE
tristate "I2s run in slave Mode codec run in Master"
config SND_CODEC_SOC_MASTER
tristate "Codec run in Master"
config SND_ROCKCHIP_SOC_MASTER
tristate "I2s run in master Mode codec run in Master"
config SND_CODEC_SOC_SLAVE
tristate "Codec run in Slave"
endchoice
endif

186
sound/soc/rk2818/rk2818_wm8994.c Executable file
View File

@@ -0,0 +1,186 @@
/*
* rk2818_wm8988.c -- SoC audio for rockchip
*
* Driver for rockchip wm8988 audio
* Copyright (C) 2009 lhh
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/rk2818_iomap.h>
#include "../codecs/wm8994.h"
#include "rk2818_pcm.h"
#include "rk2818_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk2818_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/*by Vincent Hsiung for EQ Vol Change*/
#define HW_PARAMS_FLAG_EQVOL_ON 0x21
#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
{
ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
}
else
{
/* set codec DAI configuration */
#if defined (CONFIG_SND_ROCKCHIP_SOC_MASTER)
ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif
#if defined (CONFIG_SND_ROCKCHIP_SOC_SLAVE)
ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM );
#endif
if (ret < 0)
return ret;
/* set cpu DAI configuration */
#if defined (CONFIG_SND_ROCKCHIP_SOC_MASTER)
ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
#endif
#if defined (CONFIG_SND_ROCKCHIP_SOC_SLAVE)
ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif
if (ret < 0)
return ret;
}
return 0;
}
static const struct snd_soc_dapm_widget rk2818_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[]= {
{"Audio Out", NULL, "LOUT1"},
{"Audio Out", NULL, "ROUT1"},
{"Line in", NULL, "RINPUT1"},
{"Line in", NULL, "LINPUT1"},
{"Micn", NULL, "RINPUT2"},
{"Micp", NULL, "LINPUT2"},
};
/*
* Logic for a wm8994 as connected on a rockchip board.
*/
static int rk2818_wm8994_init(struct snd_soc_codec *codec)
{
struct snd_soc_dai *codec_dai = &codec->dai[0];
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
12000000, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8994 SYSCLK: %d\n", ret);
return ret;
}
/* Add specific widgets */
snd_soc_dapm_new_controls(codec, rk2818_dapm_widgets,
ARRAY_SIZE(rk2818_dapm_widgets));
snd_soc_dapm_nc_pin(codec, "LOUT2");
snd_soc_dapm_nc_pin(codec, "ROUT2");
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_sync(codec);
return 0;
}
static struct snd_soc_ops rk2818_ops = {
.hw_params = rk2818_hw_params,
};
static struct snd_soc_dai_link rk2818_dai = {
.name = "WM8994",
.stream_name = "WM8994 PCM",
.cpu_dai = &rk2818_i2s_dai,
.codec_dai = &wm8994_dai,
.init = rk2818_wm8994_init,
.ops = &rk2818_ops,
};
static struct snd_soc_card snd_soc_card_rk2818 = {
.name = "RK2818_WM8994",
.platform = &rk2818_soc_platform,
.dai_link = &rk2818_dai,
.num_links = 1,
};
static struct snd_soc_device rk2818_snd_devdata = {
.card = &snd_soc_card_rk2818,
.codec_dev = &soc_codec_dev_wm8994,
};
static struct platform_device *rk2818_snd_device;
static int __init audio_card_init(void)
{
int ret =0;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
rk2818_snd_device = platform_device_alloc("soc-audio", -1);
if (!rk2818_snd_device) {
DBG("platform device allocation failed\n");
ret = -ENOMEM;
return ret;
}
platform_set_drvdata(rk2818_snd_device, &rk2818_snd_devdata);
rk2818_snd_devdata.dev = &rk2818_snd_device->dev;
ret = platform_device_add(rk2818_snd_device);
if (ret) {
DBG("platform device add failed\n");
platform_device_put(rk2818_snd_device);
}
return ret;
}
static void __exit audio_card_exit(void)
{
platform_device_unregister(rk2818_snd_device);
}
module_init(audio_card_init);
module_exit(audio_card_exit);
/* Module information */
MODULE_AUTHOR("lhh lhh@rock-chips.com");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");