From: huang zhibao Date: Wed, 4 Mar 2015 02:52:18 +0000 (+0800) Subject: add support rk1000 codec and tvencoder X-Git-Tag: firefly_0821_release~4263^2~26 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=be1a63299356559f0744509e7d3561f52e349e86;p=firefly-linux-kernel-4.4.55.git add support rk1000 codec and tvencoder --- diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e2422f44a4c1..f5d4668bd01e 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1226,6 +1226,14 @@ config MFD_WM8994 core support for the WM8994, in order to use the actual functionaltiy of the device other drivers must be enabled. +config MFD_RK1000 + bool "RK1000 Multimedia support" + depends on I2C=y && GPIOLIB + select MFD_CORE + help + if you say yes here you get support for the RK1000, with func as + TVEncoder CODEC. + config MFD_RK610 bool "RK610(Jetta) Multimedia support" depends on I2C=y && GPIOLIB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ff346f12f533..39c29f11aa3d 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -168,6 +168,7 @@ obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o obj-$(CONFIG_VEXPRESS_SPC) += vexpress-spc.o obj-$(CONFIG_MFD_RETU) += retu-mfd.o +obj-$(CONFIG_MFD_RK1000) += rk1000-core.o obj-$(CONFIG_MFD_RK610) += rk610-core.o obj-$(CONFIG_MFD_AS3711) += as3711.o obj-$(CONFIG_MFD_RK616) += rk616-core.o rk616-vif.o diff --git a/drivers/mfd/rk1000-core.c b/drivers/mfd/rk1000-core.c new file mode 100755 index 000000000000..09d43d674906 --- /dev/null +++ b/drivers/mfd/rk1000-core.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK1000_CORE_DBG 0 + +#if RK1000_CORE_DBG +#define DBG(x...) pr_info(x) +#else +#define DBG(x...) +#endif + +#define CTRL_ADC 0x00 +#define CTRL_CODEC 0x01 +#define CTRL_I2C 0x02 +#define CTRL_TVE 0x03 +#define RGB2CCIR_RESET 0x04 +#define ADC_START 0x05 + +struct rk1000 { + struct i2c_client *client; + struct device *dev; + struct dentry *debugfs_dir; + struct ioctrl io_power; + struct ioctrl io_reset; +}; + +static struct rk1000 *rk1000; + +void rk1000_reset_ctrl(int enable) +{ + DBG("rk1000_reset_ctrl\n"); + if (rk1000 && gpio_is_valid(rk1000->io_reset.gpio)) { + if (enable) { + gpio_set_value(rk1000->io_reset.gpio, + !(rk1000->io_reset.active)); + } else { + DBG("rk1000 reset pull low\n"); + gpio_set_value(rk1000->io_reset.gpio, + (rk1000->io_reset.active)); + } + } +} + +int rk1000_i2c_send(const u8 addr, const u8 reg, const u8 value) +{ + struct i2c_adapter *adap; + struct i2c_msg msg; + int ret; + char buf[2]; + + if (rk1000 == NULL || rk1000->client == NULL) { + DBG("rk1000 not init!\n"); + return -1; + } + adap = rk1000->client->adapter; + buf[0] = reg; + buf[1] = value; + msg.addr = addr; + msg.flags = rk1000->client->flags; + msg.len = 2; + msg.buf = buf; + msg.scl_rate = RK1000_I2C_RATE; + ret = i2c_transfer(adap, &msg, 1); + if (ret != 1) { + DBG("rk1000 control i2c write err,ret =%d\n", ret); + return -1; + } + return 0; +} + +int rk1000_i2c_recv(const u8 addr, const u8 reg, const char *buf) +{ + struct i2c_adapter *adap; + struct i2c_msg msgs[2]; + int ret; + + if (rk1000 == NULL || rk1000->client == NULL) { + DBG("rk1000 not init!\n"); + return -1; + } + adap = rk1000->client->adapter; + msgs[0].addr = addr; + msgs[0].flags = rk1000->client->flags; + msgs[0].len = 1; + msgs[0].buf = (unsigned char *)(®); + msgs[0].scl_rate = RK1000_I2C_RATE; + msgs[1].addr = addr; + msgs[1].flags = rk1000->client->flags | I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = (unsigned char *)buf; + msgs[1].scl_rate = RK1000_I2C_RATE; + ret = i2c_transfer(adap, msgs, 2); + return (ret == 2) ? 0 : -1; +} + + +#ifdef CONFIG_PM +static int rk1000_control_suspend(struct device *dev) +{ + int ret; + + DBG("rk1000_control_suspend\n"); + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x22); + DBG("ret=0x%x\n", ret); + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x00); + DBG("ret=0x%x\n", ret); + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x07); + DBG("ret=0x%x\n", ret); + rk1000_reset_ctrl(0); + return 0; +} + +static int rk1000_control_resume(struct device *dev) +{ + int ret; + + rk1000_reset_ctrl(1); + DBG("rk1000_control_resume\n"); + /* ADC power off */ + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_ADC, 0x88); + DBG("ret=0x%x\n", ret); + #ifdef CONFIG_SND_SOC_RK1000 + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x00); + #else + ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x0d); + #endif + DBG("ret=0x%x\n", ret); + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_I2C, 0x22); + DBG("ret=0x%x\n", ret); + /* rk1000_codec_reg_set(); */ + return 0; +} +#endif + + + +static int rk1000_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *rk1000_np; + enum of_gpio_flags flags; + int ret; + + DBG("[%s] start\n", __func__); + rk1000 = kmalloc(sizeof(*rk1000), GFP_KERNEL); + if (!rk1000) { + dev_err(&client->dev, ">> rk1000 core inf kmalloc fail!"); + return -ENOMEM; + } + memset(rk1000, 0, sizeof(struct rk1000)); + rk1000->client = client; + rk1000->dev = &client->dev; + rk1000_np = rk1000->dev->of_node; + /********Get reset pin***********/ + rk1000->io_reset.gpio = of_get_named_gpio_flags(rk1000_np, + "gpio-reset", + 0, &flags); + if (!gpio_is_valid(rk1000->io_reset.gpio)) { + DBG("invalid rk1000->io_reset.gpio: %d\n", + rk1000->io_reset.gpio); + ret = -1; + goto err; + } + ret = gpio_request(rk1000->io_reset.gpio, "rk1000-reset-io"); + if (ret != 0) { + DBG("gpio_request rk1000->io_reset.gpio invalid: %d\n", + rk1000->io_reset.gpio); + goto err; + } + rk1000->io_reset.active = !(flags & OF_GPIO_ACTIVE_LOW); + gpio_direction_output(rk1000->io_reset.gpio, + !(rk1000->io_reset.active)); + msleep(20); + /********Get power pin***********/ + rk1000->io_power.gpio = of_get_named_gpio_flags(rk1000_np, + "gpio-power", + 0, &flags); + if (gpio_is_valid(rk1000->io_power.gpio)) { + ret = gpio_request(rk1000->io_power.gpio, "rk1000-power-io"); + if (ret != 0) { + DBG("gpio_request rk1000->io_power.gpio invalid: %d\n", + rk1000->io_power.gpio); + goto err; + } + rk1000->io_power.active = !(flags & OF_GPIO_ACTIVE_LOW); + gpio_direction_output(rk1000->io_power.gpio, + rk1000->io_power.active); + } + /********rk1000 reset***********/ + gpio_set_value(rk1000->io_reset.gpio, rk1000->io_reset.active); + msleep(100); + gpio_set_value(rk1000->io_reset.gpio, !(rk1000->io_reset.active)); + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_ADC, 0x88); + #ifdef CONFIG_SND_SOC_RK1000 + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x00); + #else + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x0d); + #endif + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_I2C, 0x22); + rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x00); + DBG("rk1000 probe ok\n"); + return 0; +err: + kfree(rk1000); + rk1000 = NULL; + return ret; +} + +static int rk1000_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id rk1000_id[] = { + { "rk1000_control", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rk1000_id); + +static const struct dev_pm_ops rockchip_rk1000_pm_ops = { + .suspend_late = rk1000_control_suspend, + .resume_early = rk1000_control_resume, +}; + +static struct i2c_driver rk1000_driver = { + .driver = { + .name = "rk1000_control", + #ifdef CONFIG_PM + .pm = &rockchip_rk1000_pm_ops, + #endif + }, + .probe = rk1000_probe, + .remove = rk1000_remove, + .id_table = rk1000_id, +}; + + +static int __init rk1000_init(void) +{ + return i2c_add_driver(&rk1000_driver); +} + +static void __exit rk1000_exit(void) +{ + i2c_del_driver(&rk1000_driver); +} + +fs_initcall_sync(rk1000_init); +module_exit(rk1000_exit); + + +MODULE_DESCRIPTION("RK1000 control driver"); +MODULE_AUTHOR("Rock-chips, "); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/rockchip/tve/Kconfig b/drivers/video/rockchip/tve/Kconfig index e165ee3250ef..83c2c0e58a38 100644 --- a/drivers/video/rockchip/tve/Kconfig +++ b/drivers/video/rockchip/tve/Kconfig @@ -8,6 +8,7 @@ menuconfig RK_TVENCODER help Support RockChip TV Encoder if you say y here. +source "drivers/video/rockchip/tve/rk1000/Kconfig" source "drivers/video/rockchip/tve/rk3036/Kconfig" source "drivers/video/rockchip/tve/rk610/Kconfig" diff --git a/drivers/video/rockchip/tve/Makefile b/drivers/video/rockchip/tve/Makefile index ea651687c417..ae38690889fd 100644 --- a/drivers/video/rockchip/tve/Makefile +++ b/drivers/video/rockchip/tve/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_RK610_TVOUT) += rk610/ obj-$(CONFIG_RK3036_TV_ENCODER) += rk3036/ +obj-$(CONFIG_RK1000_TVOUT) += rk1000/ diff --git a/drivers/video/rockchip/tve/rk1000/Kconfig b/drivers/video/rockchip/tve/rk1000/Kconfig new file mode 100755 index 000000000000..a708973a5c6c --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/Kconfig @@ -0,0 +1,18 @@ +# +# TV Encoder RK1000 drivers configuration +# + +config RK1000_TVOUT + bool "RK1000 TV Encoder support" + depends on RK_TVENCODER + select MFD_RK1000 + help + Support rk1000 to output YPbPr and CVBS. + +config RK1000_TVOUT_YPbPr + bool "Support YPbPr Output" + depends on RK1000_TVOUT +config RK1000_TVOUT_CVBS + bool "Support CVBS Output" + depends on RK1000_TVOUT + diff --git a/drivers/video/rockchip/tve/rk1000/Makefile b/drivers/video/rockchip/tve/rk1000/Makefile new file mode 100755 index 000000000000..d229b49f940a --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the RK1000 tv control. +# +obj-$(CONFIG_RK1000_TVOUT) += rk1000_tve.o +obj-$(CONFIG_RK1000_TVOUT_YPbPr) += rk1000_tve_ypbpr.o +obj-$(CONFIG_RK1000_TVOUT_CVBS) += rk1000_tve_cvbs.o diff --git a/drivers/video/rockchip/tve/rk1000/rk1000_tve.c b/drivers/video/rockchip/tve/rk1000/rk1000_tve.c new file mode 100755 index 000000000000..483ae0336d1b --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/rk1000_tve.c @@ -0,0 +1,375 @@ +/* + * rk1000_tv.c + * + * Driver for rockchip rk1000 tv control + * Copyright (C) 2009 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#include +#include +#endif +#include "rk1000_tve.h" + +struct rk1000_tve rk1000_tve; + + +int rk1000_tv_write_block(u8 reg, u8 *buf, u8 len) +{ + int i, ret; + + for (i = 0; i < len; i++) { + ret = rk1000_i2c_send(I2C_ADDR_TVE, reg + i, buf[i]); + if (ret) + break; + } + return ret; +} + +int rk1000_control_write_block(u8 reg, u8 *buf, u8 len) +{ + int i; + int ret; + + for (i = 0; i < len; i++) { + ret = rk1000_i2c_send(I2C_ADDR_CTRL, reg + i, buf[i]); + if (ret) + break; + } + return ret; +} + +int rk1000_switch_fb(const struct fb_videomode *modedb, int tv_mode) +{ + struct rk_screen *screen; + + if (modedb == NULL) + return -1; + screen = kzalloc(sizeof(*screen), GFP_KERNEL); + if (screen == NULL) + return -1; + memset(screen, 0, sizeof(*screen)); + /* screen type & face */ + screen->type = SCREEN_RGB; + screen->face = OUT_P888; + screen->mode = *modedb; + screen->mode.vmode = 0; + /* Pin polarity */ + if (FB_SYNC_HOR_HIGH_ACT & modedb->sync) + screen->pin_hsync = 1; + else + screen->pin_hsync = 0; + if (FB_SYNC_VERT_HIGH_ACT & modedb->sync) + screen->pin_vsync = 1; + else + screen->pin_vsync = 0; + screen->pin_den = 0; + screen->pin_dclk = 1; + /* Swap rule */ + screen->swap_rb = 0; + screen->swap_rg = 0; + screen->swap_gb = 0; + screen->swap_delta = 0; + screen->swap_dumy = 0; + screen->overscan.left = 95; + screen->overscan.top = 95; + screen->overscan.right = 95; + screen->overscan.bottom = 95; + /* Operation function*/ + screen->init = NULL; + screen->standby = NULL; + switch (tv_mode) { + #ifdef CONFIG_RK1000_TVOUT_CVBS + case TVOUT_CVBS_NTSC: + screen->init = rk1000_tv_ntsc_init; + break; + case TVOUT_CVBS_PAL: + screen->init = rk1000_tv_pal_init; + break; + #endif + #ifdef CONFIG_RK1000_TVOUT_YPBPR + case TVOUT_YPBPR_720X480P_60: + screen->init = rk1000_tv_ypbpr480_init; + break; + case TVOUT_YPBPR_720X576P_50: + screen->init = rk1000_tv_ypbpr576_init; + break; + case TVOUT_YPBPR_1280X720P_50: + screen->init = rk1000_tv_ypbpr720_50_init; + break; + case TVOUT_YPBPR_1280X720P_60: + screen->init = rk1000_tv_ypbpr720_60_init; + break; + #endif + default: + kfree(screen); + return -1; + } + rk_fb_switch_screen(screen, 1 , rk1000_tve.video_source); + rk1000_tve.mode = tv_mode; + kfree(screen); + if (gpio_is_valid(rk1000_tve.io_switch.gpio)) { + if (tv_mode < TVOUT_YPBPR_720X480P_60) + gpio_direction_output(rk1000_tve.io_switch.gpio, + !(rk1000_tve.io_switch.active)); + else + gpio_direction_output(rk1000_tve.io_switch.gpio, + rk1000_tve.io_switch.active); + } + return 0; +} + +int rk1000_tv_standby(int type) +{ + unsigned char val; + int ret; + int ypbpr; + int cvbs; + struct rk_screen screen; + + ypbpr = 0; + cvbs = 0; + if (rk1000_tve.ypbpr) + ypbpr = rk1000_tve.ypbpr->enable; + if (rk1000_tve.cvbs) + cvbs = rk1000_tve.cvbs->enable; + if (cvbs || ypbpr) + return 0; + val = 0x00; + ret = rk1000_control_write_block(0x03, &val, 1); + if (ret < 0) { + pr_err("rk1000_control_write_block err!\n"); + return ret; + } + val = 0x07; + ret = rk1000_tv_write_block(0x03, &val, 1); + if (ret < 0) { + pr_err("rk1000_tv_write_block err!\n"); + return ret; + } + screen.type = SCREEN_RGB; + rk_fb_switch_screen(&screen, 0 , rk1000_tve.video_source); + pr_err("rk1000 tve standby\n"); + return 0; +} + +static int rk1000_tve_initial(void) +{ + struct rk_screen screen; + + /* RK1000 tvencoder i2c reg need dclk, so we open lcdc.*/ + memset(&screen, 0, sizeof(struct rk_screen)); + /* screen type & face */ + screen.type = SCREEN_RGB; + screen.face = OUT_P888; + /* Screen size */ + screen.mode.xres = 720; + screen.mode.yres = 480; + /* Timing */ + screen.mode.pixclock = 27000000; + screen.mode.refresh = 60; + screen.mode.left_margin = 116; + screen.mode.right_margin = 16; + screen.mode.hsync_len = 6; + screen.mode.upper_margin = 25; + screen.mode.lower_margin = 14; + screen.mode.vsync_len = 6; + rk_fb_switch_screen(&screen, 2 , rk1000_tve.video_source); + /* Power down RK1000 output DAC. */ + return rk1000_i2c_send(I2C_ADDR_TVE, 0x03, 0x07); +} + + +static void rk1000_early_suspend(void *h) +{ + pr_info("rk1000_early_suspend\n"); + if (rk1000_tve.ypbpr) { + rk1000_tve.ypbpr->ddev->ops->setenable(rk1000_tve.ypbpr->ddev, + 0); + rk1000_tve.ypbpr->suspend = 1; + } + if (rk1000_tve.cvbs) { + rk1000_tve.cvbs->ddev->ops->setenable(rk1000_tve.cvbs->ddev, + 0); + rk1000_tve.cvbs->suspend = 1; + } +} + + +static void rk1000_early_resume(void *h) +{ + pr_info("rk1000 tve exit early resume\n"); + if (rk1000_tve.cvbs) { + rk1000_tve.cvbs->suspend = 0; + if (rk1000_tve.mode < TVOUT_YPBPR_720X480P_60) + rk_display_device_enable((rk1000_tve.cvbs)->ddev); + } + if (rk1000_tve.ypbpr) { + rk1000_tve.ypbpr->suspend = 0; + if (rk1000_tve.mode > TVOUT_CVBS_PAL) + rk_display_device_enable((rk1000_tve.ypbpr)->ddev); + } +} + + +static int rk1000_fb_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_event *event; + int blank_mode; + + event = data; + blank_mode = *((int *)event->data); + if (action == FB_EARLY_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + break; + default: + rk1000_early_suspend(NULL); + break; + } + } else if (action == FB_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + rk1000_early_resume(NULL); + break; + default: + break; + } + } + return NOTIFY_OK; +} + +static struct notifier_block rk1000_fb_notifier = { + .notifier_call = rk1000_fb_event_notify, +}; + +static int rk1000_tve_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *tve_np; + enum of_gpio_flags flags; + int rc; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + rc = -ENODEV; + goto failout; + } + + memset(&rk1000_tve, 0, sizeof(struct rk1000_tve)); + rk1000_tve.client = client; +#ifdef CONFIG_OF + tve_np = client->dev.of_node; + rk1000_tve.io_switch.gpio = of_get_named_gpio_flags(tve_np, + "gpio-reset", + 0, &flags); + if (gpio_is_valid(rk1000_tve.io_switch.gpio)) { + rc = gpio_request(rk1000_tve.io_switch.gpio, + "rk1000-tve-swicth-io"); + if (!rc) { + rk1000_tve.io_switch.active = !(flags & + OF_GPIO_ACTIVE_LOW); + gpio_direction_output(rk1000_tve.io_switch.gpio, + !(rk1000_tve.io_switch.active)); + } else + pr_err("gpio request rk1000-tve-swicth-io err: %d\n", + rk1000_tve.io_switch.gpio); + } + of_property_read_u32(tve_np, "rockchip,source", &(rc)); + rk1000_tve.video_source = rc; + of_property_read_u32(tve_np, "rockchip,prop", &(rc)); + rk1000_tve.property = rc - 1; + pr_err("video src is lcdc%d, prop is %d\n", rk1000_tve.video_source, + rk1000_tve.property); +#endif + rk1000_tve.mode = RK1000_TVOUT_DEAULT; + rc = rk1000_tve_initial(); + if (rc) { + dev_err(&client->dev, "rk1000 tvencoder probe error %d\n", rc); + return -EINVAL; + } + +#ifdef CONFIG_RK1000_TVOUT_YPBPR + rk1000_register_display_ypbpr(&client->dev); +#endif + +#ifdef CONFIG_RK1000_TVOUT_CVBS + rk1000_register_display_cvbs(&client->dev); +#endif + #ifdef CONFIG_HAS_EARLYSUSPEND + rk1000_tve.early_suspend.suspend = rk1000_early_suspend; + rk1000_tve.early_suspend.resume = rk1000_early_resume; + rk1000_tve.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 11; + register_early_suspend(&(rk1000_tve.early_suspend)); + #endif + fb_register_client(&rk1000_fb_notifier); + pr_info("rk1000 tvencoder ver 2.0 probe ok\n"); + return 0; +failout: + kfree(client); + client = NULL; + return rc; +} + +static int rk1000_tve_remove(struct i2c_client *client) +{ + return 0; +} + +static void rk1000_tve_shutdown(struct i2c_client *client) +{ + rk1000_i2c_send(I2C_ADDR_TVE, 0x03, 0x07); +} + +static const struct i2c_device_id rk1000_tve_id[] = { + { "rk1000_tve", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rk1000_tve_id); + +static struct i2c_driver rk1000_tve_driver = { + .driver = { + .name = "rk1000_tve", + }, + .id_table = rk1000_tve_id, + .probe = rk1000_tve_probe, + .remove = rk1000_tve_remove, + .shutdown = rk1000_tve_shutdown, +}; + +static int __init rk1000_tve_init(void) +{ + int ret; + + ret = i2c_add_driver(&rk1000_tve_driver); + if (ret < 0) + pr_err("i2c_add_driver err, ret = %d\n", ret); + return ret; +} + +static void __exit rk1000_tve_exit(void) +{ + i2c_del_driver(&rk1000_tve_driver); +} + +late_initcall(rk1000_tve_init); +module_exit(rk1000_tve_exit); + +/* Module information */ +MODULE_DESCRIPTION("ROCKCHIP rk1000 TV Encoder "); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/rockchip/tve/rk1000/rk1000_tve.h b/drivers/video/rockchip/tve/rk1000/rk1000_tve.h new file mode 100755 index 000000000000..996506f7925e --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/rk1000_tve.h @@ -0,0 +1,78 @@ +#ifndef _RK1000_TVE_H +#define _RK1000_TVE_H +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +/******************* TVOUT OUTPUT TYPE **********************/ +struct rk1000_monspecs { + struct rk_display_device *ddev; + unsigned int enable; + unsigned int suspend; + struct fb_videomode *mode; + struct list_head modelist; + unsigned int mode_set; +}; + +struct rk1000_tve { + struct device *dev; + struct i2c_client *client; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; + #endif + struct ioctrl io_switch; + int video_source; + int property; + int mode; + struct rk1000_monspecs *cvbs; + struct rk1000_monspecs *ypbpr; +}; + +extern struct rk1000_tve rk1000_tve; + +enum { + TVOUT_CVBS_NTSC = 1, + TVOUT_CVBS_PAL, + TVOUT_YPBPR_720X480P_60, + TVOUT_YPBPR_720X576P_50, + TVOUT_YPBPR_1280X720P_50, + TVOUT_YPBPR_1280X720P_60 +}; + +enum { + RK1000_TVOUT_CVBS = 0, + RK1000_TVOUT_YC, + RK1000_TVOUT_YPBPR, +}; +#ifdef CONFIG_RK1000_TVOUT_CVBS +#define RK1000_TVOUT_DEAULT TVOUT_CVBS_NTSC +#else +#define RK1000_TVOUT_DEAULT TVOUT_YPBPR_1280X720P_60 +#endif + +int rk1000_control_write_block(u8 reg, u8 *buf, u8 len); +int rk1000_tv_write_block(u8 reg, u8 *buf, u8 len); +int rk1000_tv_standby(int type); +int rk1000_switch_fb(const struct fb_videomode *modedb, int tv_mode); +int rk1000_register_display(struct device *parent); + +#ifdef CONFIG_RK1000_TVOUT_YPBPR +int rk1000_tv_ypbpr480_init(void); +int rk1000_tv_ypbpr576_init(void); +int rk1000_tv_ypbpr720_50_init(void); +int rk1000_tv_ypbpr720_60_init(void); +int rk1000_register_display_ypbpr(struct device *parent); +#endif + +#ifdef CONFIG_RK1000_TVOUT_CVBS +int rk1000_tv_ntsc_init(void); +int rk1000_tv_pal_init(void); +int rk1000_register_display_cvbs(struct device *parent); +#endif + +#endif + diff --git a/drivers/video/rockchip/tve/rk1000/rk1000_tve_cvbs.c b/drivers/video/rockchip/tve/rk1000/rk1000_tve_cvbs.c new file mode 100755 index 000000000000..4e4e503cbae3 --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/rk1000_tve_cvbs.c @@ -0,0 +1,182 @@ +#include +#include +#include "rk1000_tve.h" + + + +static const struct fb_videomode rk1000_cvbs_mode[] = { + {"NTSC", 60, 720, 480, 27000000, 116, 16, 25, 14, 6, 6, 0, 1, 0}, + {"PAL", 50, 720, 576, 27000000, 126, 12, 37, 6, 6, 6, 0, 1, 0}, +}; + +static struct rk1000_monspecs cvbs_monspecs; + +int rk1000_tv_ntsc_init(void) +{ + unsigned char tv_encoder_regs[] = {0x00, 0x00, 0x00, 0x03, 0x00, 0x00}; + unsigned char tv_encoder_control_regs[] = {0x43, 0x01}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs + i, 1); + if (ret < 0) { + pr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i + 3, + tv_encoder_control_regs + i, + 1); + if (ret < 0) { + pr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + + return 0; +} + +int rk1000_tv_pal_init(void) +{ + unsigned char tv_encoder_regs[] = {0x06, 0x00, 0x00, 0x03, 0x00, 0x00}; + unsigned char tv_encoder_control_regs[] = {0x41, 0x01}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs+i, 1); + if (ret < 0) { + pr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i + 3, + tv_encoder_control_regs + i, + 1); + if (ret < 0) { + pr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + return 0; +} + +static int rk1000_cvbs_set_enable(struct rk_display_device *device, int enable) +{ + if (cvbs_monspecs.suspend) + return 0; + if ((cvbs_monspecs.enable != enable) || + (cvbs_monspecs.mode_set != rk1000_tve.mode)) { + if ((enable == 0) && cvbs_monspecs.enable) { + cvbs_monspecs.enable = 0; + rk1000_tv_standby(RK1000_TVOUT_CVBS); + } else if (enable == 1) { + rk1000_switch_fb(cvbs_monspecs.mode, + cvbs_monspecs.mode_set); + cvbs_monspecs.enable = 1; + } + } + return 0; +} + +static int rk1000_cvbs_get_enable(struct rk_display_device *device) +{ + return cvbs_monspecs.enable; +} + +static int rk1000_cvbs_get_status(struct rk_display_device *device) +{ + if (rk1000_tve.mode < TVOUT_YPBPR_720X480P_60) + return 1; + else + return 0; +} + +static int rk1000_cvbs_get_modelist(struct rk_display_device *device, + struct list_head **modelist) +{ + *modelist = &(cvbs_monspecs.modelist); + return 0; +} + +static int rk1000_cvbs_set_mode(struct rk_display_device *device, + struct fb_videomode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rk1000_cvbs_mode); i++) { + if (fb_mode_is_equal(&rk1000_cvbs_mode[i], mode)) { + if (((i + 1) != rk1000_tve.mode)) { + cvbs_monspecs.mode_set = i + 1; + cvbs_monspecs.mode = (struct fb_videomode *) + &rk1000_cvbs_mode[i]; + } + return 0; + } + } + return -1; +} + +static int rk1000_cvbs_get_mode(struct rk_display_device *device, + struct fb_videomode *mode) +{ + *mode = *(cvbs_monspecs.mode); + return 0; +} + +static struct rk_display_ops rk1000_cvbs_display_ops = { + .setenable = rk1000_cvbs_set_enable, + .getenable = rk1000_cvbs_get_enable, + .getstatus = rk1000_cvbs_get_status, + .getmodelist = rk1000_cvbs_get_modelist, + .setmode = rk1000_cvbs_set_mode, + .getmode = rk1000_cvbs_get_mode, +}; + +static int rk1000_display_cvbs_probe(struct rk_display_device *device, + void *devdata) +{ + device->owner = THIS_MODULE; + strcpy(device->type, "TV"); + device->name = "cvbs"; + device->priority = DISPLAY_PRIORITY_TV; + device->property = rk1000_tve.property; + device->priv_data = devdata; + device->ops = &rk1000_cvbs_display_ops; + return 1; +} + +static struct rk_display_driver display_rk1000_cvbs = { + .probe = rk1000_display_cvbs_probe, +}; + +int rk1000_register_display_cvbs(struct device *parent) +{ + int i; + + memset(&cvbs_monspecs, 0, sizeof(struct rk1000_monspecs)); + INIT_LIST_HEAD(&cvbs_monspecs.modelist); + for (i = 0; i < ARRAY_SIZE(rk1000_cvbs_mode); i++) + display_add_videomode(&rk1000_cvbs_mode[i], + &cvbs_monspecs.modelist); + if (rk1000_tve.mode < TVOUT_YPBPR_720X480P_60) { + cvbs_monspecs.mode = (struct fb_videomode *) + &(rk1000_cvbs_mode[rk1000_tve.mode - 1]); + cvbs_monspecs.mode_set = rk1000_tve.mode; + } else { + cvbs_monspecs.mode = (struct fb_videomode *) + &(rk1000_cvbs_mode[0]); + cvbs_monspecs.mode_set = TVOUT_CVBS_NTSC; + } + cvbs_monspecs.ddev = rk_display_device_register(&display_rk1000_cvbs, + parent, NULL); + rk1000_tve.cvbs = &cvbs_monspecs; + if (rk1000_tve.mode < TVOUT_YPBPR_720X480P_60) + rk_display_device_enable(cvbs_monspecs.ddev); + return 0; +} diff --git a/drivers/video/rockchip/tve/rk1000/rk1000_tve_ypbpr.c b/drivers/video/rockchip/tve/rk1000/rk1000_tve_ypbpr.c new file mode 100755 index 000000000000..dcaa5bc661f0 --- /dev/null +++ b/drivers/video/rockchip/tve/rk1000/rk1000_tve_ypbpr.c @@ -0,0 +1,239 @@ +#include +#include +#include "rk1000_tve.h" + +static const struct fb_videomode rk1000_ypbpr_mode[] = { + {"YPBPR480P", 60, 720, 480, 27000000, 70, 6, 30, 9, 62, 6, 0, 0, 0}, + {"YPBPR576P", 50, 720, 576, 27000000, 74, 6, 39, 5, 64, 5, 0, 0, 0}, + {"YPBPR720P@50", 50, 1280, 720, 74250000, 660, 0, 20, 5, 40, + 5, 0, 0, 0}, + {"YPbPR720P@60", 60, 1280, 720, 74250000, 330, 0, 20, 5, 40, + 5, 0, 0, 0}, +}; + +static struct rk1000_monspecs ypbpr_monspecs; + +int rk1000_tv_ypbpr480_init(void) +{ + unsigned char tv_encoder_regs[] = {0x00, 0x00, 0x40, 0x08, 0x00, + 0x02, 0x17, 0x0A, 0x0A}; + unsigned char tv_encoder_control_regs[] = {0x00}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs + i, 1); + if (ret < 0) { + prr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i+3, + tv_encoder_control_regs+i, + 1); + if (ret < 0) { + prr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + return 0; +} + +int rk1000_tv_ypbpr576_init(void) +{ + unsigned char tv_encoder_regs[] = {0x06, 0x00, 0x40, 0x08, 0x00, + 0x01, 0x17, 0x0A, 0x0A}; + unsigned char tv_encoder_control_regs[] = {0x00}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs+i, 1); + if (ret < 0) { + prr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i + 3, + tv_encoder_control_regs + i, + 1); + if (ret < 0) { + prr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + return 0; +} + +int rk1000_tv_ypbpr720_50_init(void) +{ + unsigned char tv_encoder_regs[] = {0x06, 0x00, 0x40, 0x08, + 0x00, 0x13, 0x17, 0x0A, 0x0A}; + unsigned char tv_encoder_control_regs[] = {0x00}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs+i, 1); + if (ret < 0) { + prr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i+3, + tv_encoder_control_regs+i, + 1); + if (ret < 0) { + prr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + return 0; +} + +int rk1000_tv_ypbpr720_60_init(void) +{ + unsigned char tv_encoder_regs[] = {0x06, 0x00, 0x40, 0x08, 0x00, + 0x17, 0x17, 0x0A, 0x0A}; + unsigned char tv_encoder_control_regs[] = {0x00}; + int i; + int ret; + + for (i = 0; i < sizeof(tv_encoder_regs); i++) { + ret = rk1000_tv_write_block(i, tv_encoder_regs + i, 1); + if (ret < 0) { + prr_err("rk1000_tv_write_block err!\n"); + return ret; + } + } + for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { + ret = rk1000_control_write_block(i + 3, + tv_encoder_control_regs + i, + 1); + if (ret < 0) { + prr_err("rk1000_control_write_block err!\n"); + return ret; + } + } + return 0; +} + +static int rk1000_ypbpr_set_enable(struct rk_display_device *device, + int enable) +{ + if (ypbpr_monspecs.suspend) + return 0; + if (ypbpr_monspecs.enable != enable || + ypbpr_monspecs.mode_set != rk1000_tve.mode) { + if (enable == 0 && ypbpr_monspecs.enable) { + ypbpr_monspecs.enable = 0; + rk1000_tv_standby(RK1000_TVOUT_YPBPR); + } else if (enable == 1) { + rk1000_switch_fb(ypbpr_monspecs.mode, + ypbpr_monspecs.mode_set); + ypbpr_monspecs.enable = 1; + } + } + return 0; +} + +static int rk1000_ypbpr_get_enable(struct rk_display_device *device) +{ + return ypbpr_monspecs.enable; +} + +static int rk1000_ypbpr_get_status(struct rk_display_device *device) +{ + if (rk1000_tve.mode > TVOUT_CVBS_PAL) + return 1; + else + return 0; +} + +static int rk1000_ypbpr_get_modelist(struct rk_display_device *device, + struct list_head **modelist) +{ + *modelist = &(ypbpr_monspecs.modelist); + return 0; +} + +static int rk1000_ypbpr_set_mode(struct rk_display_device *device, + struct fb_videomode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rk1000_ypbpr_mode); i++) { + if (fb_mode_is_equal(&rk1000_ypbpr_mode[i], mode)) { + if ((i + 3) != rk1000_tve.mode) { + ypbpr_monspecs.mode_set = i + 3; + ypbpr_monspecs.mode = (struct fb_videomode *) + &rk1000_ypbpr_mode[i]; + } + return 0; + } + } + return -1; +} + +static int rk1000_ypbpr_get_mode(struct rk_display_device *device, + struct fb_videomode *mode) +{ + *mode = *(ypbpr_monspecs.mode); + return 0; +} + +static struct rk_display_ops rk1000_ypbpr_display_ops = { + .setenable = rk1000_ypbpr_set_enable, + .getenable = rk1000_ypbpr_get_enable, + .getstatus = rk1000_ypbpr_get_status, + .getmodelist = rk1000_ypbpr_get_modelist, + .setmode = rk1000_ypbpr_set_mode, + .getmode = rk1000_ypbpr_get_mode, +}; + +static int rk1000_display_ypbpr_probe(struct rk_display_device *device, + void *devdata) +{ + device->owner = THIS_MODULE; + strcpy(device->type, "YPbPr"); + device->name = "ypbpr"; + device->priority = DISPLAY_PRIORITY_YPBPR; + device->property = rk1000_tve.property; + device->priv_data = devdata; + device->ops = &rk1000_ypbpr_display_ops; + return 1; +} + +static struct rk_display_driver display_rk1000_ypbpr = { + .probe = rk1000_display_ypbpr_probe, +}; + +int rk1000_register_display_ypbpr(struct device *parent) +{ + int i; + + memset(&ypbpr_monspecs, 0, sizeof(struct rk1000_monspecs)); + INIT_LIST_HEAD(&ypbpr_monspecs.modelist); + for (i = 0; i < ARRAY_SIZE(rk1000_ypbpr_mode); i++) + display_add_videomode(&rk1000_ypbpr_mode[i], + &ypbpr_monspecs.modelist); + if (rk1000_tve.mode > TVOUT_CVBS_PAL) { + ypbpr_monspecs.mode = (struct fb_videomode *) + &(rk1000_ypbpr_mode[rk1000_tve.mode - 3]); + ypbpr_monspecs.mode_set = rk1000_tve.mode; + } else { + ypbpr_monspecs.mode = (struct fb_videomode *) + &(rk1000_ypbpr_mode[3]); + ypbpr_monspecs.mode_set = TVOUT_YPBPR_1280X720P_60; + } + ypbpr_monspecs.ddev = rk_display_device_register(&display_rk1000_ypbpr, + parent, NULL); + rk1000_tve.ypbpr = &ypbpr_monspecs; + if (rk1000_tve.mode > TVOUT_CVBS_PAL) + rk_display_device_enable(ypbpr_monspecs.ddev); + return 0; +} diff --git a/include/linux/mfd/rk1000.h b/include/linux/mfd/rk1000.h new file mode 100755 index 000000000000..606820da7489 --- /dev/null +++ b/include/linux/mfd/rk1000.h @@ -0,0 +1,17 @@ +#ifndef __RK1000_H__ +#define __RK1000_H__ + +#define I2C_ADDR_CTRL 0x40 +#define I2C_ADDR_TVE 0x42 + +#define RK1000_I2C_RATE (100*1000) + +struct ioctrl { + int gpio; + int active; +}; + +int rk1000_i2c_send(const u8 addr, const u8 reg, const u8 value); +int rk1000_i2c_recv(const u8 addr, const u8 reg, const char *buf); + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b7ef0b9655c3..ac376f69ad8e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -119,6 +119,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5512 if I2C select SND_SOC_RK610 if I2C select SND_SOC_RK616 if I2C + select SND_SOC_RK1000 if I2C select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS select SND_SOC_WM8904 if I2C select SND_SOC_WM8940 if I2C @@ -586,6 +587,10 @@ config SND_SOC_RK616 tristate depends on MFD_RK616 +config SND_SOC_RK1000 + tristate + depends on MFD_RK1000 + config SND_SOC_RK2928 tristate depends on ARCH_RK2928 diff --git a/sound/soc/codecs/rk1000_codec.c b/sound/soc/codecs/rk1000_codec.c index a3c43c4a3413..bd979cd255a4 100755 --- a/sound/soc/codecs/rk1000_codec.c +++ b/sound/soc/codecs/rk1000_codec.c @@ -10,57 +10,61 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include #include #include +#include #include #include #include #include #include -#include -#include -#include #include -#include #include #include #include +#include #include -#include -#include - +#include +#include #include "rk1000_codec.h" -//#define RK1000_CODEC_PROC -#ifdef RK1000_CODEC_PROC -#include -#include -#include -char debug_write_read = 0; -#endif + + /* * Debug */ -#if 1 -#define DBG(x...) printk(KERN_INFO x) +#define RK1000_CODEC_DBG 0 +#if RK1000_CODEC_DBG +#define DBG(x...) pr_info(x) #else #define DBG(x...) #endif -#define err(format, arg...) \ - printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) -#define info(format, arg...) \ - printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) - -#define OUT_CAPLESS (0) //ÊÇ·ñΪÎÞµçÈÝÊä³ö£¬1:ÎÞµçÈÝÊä³ö£¬0:ÓеçÈÝÊä³ö +/*rk1000 codec proc debug*/ +#define RK1000_CODEC_PROC 1 -static struct snd_soc_codec *rk1000_codec_codec; +#define HP_OUT 0 +#define HP_IN 1 +#define USE_MIC_IN +#define USE_LPF + +#define FREQ441KHZ (0x11 << 1) +/* rk1000 output volume,DAC Digital Gain */ +/* 0x0000 ~ 0xF42 */ +#define VOLUME_OUTPUT 0xF42 +/* 0x0 ~ 0x3f(bit0-bit5) max=0x0(+6DB) min=0x3f(-60DB) Analog Gain */ +#define VOLUME_CODEC_PA 0x0 + +/* rk1000 input volume,rk610 can not adjust the recording volume */ +#define VOLUME_INPUT 0x07 + +#define OUT_CAPLESS (1) + +/* 1:set pll from rk1000 */ +#define RK1000_CTL_PLL 0 -//static u32 gVolReg = 0x0f; ///0x0f; //ÓÃÓڼǼÒôÁ¿¼Ä´æÆ÷ -//static u32 gCodecVol = 0x0f; -static u8 gR0AReg = 0; //ÓÃÓڼǼR0A¼Ä´æÆ÷µÄÖµ£¬ÓÃÓڸıä²ÉÑùÂÊǰͨ¹ýR0AÍ£Ö¹clk -static u8 gR0BReg = 0; //ÓÃÓڼǼR0B¼Ä´æÆ÷µÄÖµ£¬ÓÃÓڸıä²ÉÑùÂÊǰͨ¹ýR0BÍ£Ö¹interplateºÍdecimation -static u8 gR1314Reg = 0; //ÓÃÓڼǼR13,R14¼Ä´æÆ÷µÄÖµ£¬ÓÃÓÚFMÒôÁ¿Îª0ʱ +static u8 g_r0_a_reg; +static u8 g_r0_b_reg; /* * rk1000 register cache @@ -78,48 +82,86 @@ static const u16 rk1000_codec_reg[] = { 0x0000, 0x00ff, 0x00ff, 0x00ff, /* 0x1a */ }; +static struct snd_soc_codec *rk1000_codec_codec; /* codec private data */ struct rk1000_codec_priv { enum snd_soc_control_type control_type; - void *control_data; - unsigned int sysclk; struct snd_soc_codec codec; struct snd_pcm_hw_constraint_list *sysclk_constraints; u16 reg_cache[RK1000_CODEC_NUM_REG]; + + struct delayed_work rk1000_delayed_work; + unsigned int spk_ctrl_io; + enum of_gpio_flags flags; + /* + Some amplifiers enable a longer time. + config after pa_enable_io delay pa_enable_time(ms) + so value range is 0 - 8000. + */ + unsigned int pa_enable_time; + /* if found boot pop,set boot_depop 1 test */ + int boot_depop; + int call_enable; + int headset_status; }; + +static void spk_ctrl_fun(int status) +{ + struct rk1000_codec_priv *rk1000_codec; + + if (rk1000_codec_codec == NULL) + return; + rk1000_codec = snd_soc_codec_get_drvdata(rk1000_codec_codec); + if (rk1000_codec == NULL) + return; + if (!rk1000_codec->spk_ctrl_io) + return; + DBG("%s:: spk status = %d\n", __func__, status); + if (status) + gpio_set_value(rk1000_codec->spk_ctrl_io, + rk1000_codec->flags); + else + gpio_set_value(rk1000_codec->spk_ctrl_io, + !rk1000_codec->flags); +} + + /* * read rk1000 register cache */ -static inline unsigned int rk1000_codec_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) +static unsigned int rk1000_codec_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) { u16 *cache = codec->reg_cache; + if (reg > RK1000_CACHE_REGNUM) return -1; return cache[reg]; } -static unsigned int rk1000_codec_read(struct snd_soc_codec *codec, unsigned int r) -{ +static unsigned int rk1000_codec_read(struct snd_soc_codec *codec, + unsigned int r) +{ struct i2c_msg xfer[1]; - u8 reg = r; + int reg; int ret; - struct i2c_client *client = codec->control_data; + struct i2c_client *i2c; + reg = r; + i2c = to_i2c_client(codec->dev); /* Read register */ - xfer[0].addr = (client->addr& 0x60)|(reg); + xfer[0].addr = (i2c->addr & 0x60) | (reg); xfer[0].flags = I2C_M_RD; xfer[0].len = 1; - xfer[0].buf = ® - xfer[0].scl_rate = 100*1000; - ret = i2c_transfer(client->adapter, xfer, 1); + xfer[0].buf = (unsigned char *)® + xfer[0].scl_rate = 100000; + ret = i2c_transfer(i2c->adapter, xfer, 1); if (ret != 1) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret); return 0; } - return reg; } @@ -127,143 +169,109 @@ static unsigned int rk1000_codec_read(struct snd_soc_codec *codec, unsigned int * write rk1000 register cache */ static inline void rk1000_codec_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) + unsigned int reg, + unsigned int value) { - u16 *cache = codec->reg_cache; + u16 *cache; + + cache = codec->reg_cache; if (reg > RK1000_CACHE_REGNUM) return; cache[reg] = value; } static int rk1000_codec_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) + unsigned int value) { +#ifdef CONFIG_MODEM_SOUND + struct rk1000_codec_priv *rk1000_codec; +#endif u8 data[2]; struct i2c_client *i2c; - DBG("Enter-%s::reg=0x%02X, value=0x%02X\n",__FUNCTION__, reg, value); + + i2c = to_i2c_client(codec->dev); +#ifdef CONFIG_MODEM_SOUND + rk1000_codec = snd_soc_codec_get_drvdata(rk1000_codec_codec); + if (rk1000_codec->call_enable) + return 0; +#endif + DBG("Enter::%s, %d, reg=0x%02X, value=0x%02X\n", __func__, + __LINE__, reg, value); data[0] = value & 0x00ff; - rk1000_codec_write_reg_cache (codec, reg, value); - i2c = (struct i2c_client *)codec->control_data; i2c->addr = (i2c->addr & 0x60)|reg; - if (codec->hw_write(codec->control_data, data, 1) == 1){ -// DBG("================%s Run OK====%d============\n",__FUNCTION__,__LINE__); + if (codec->hw_write(i2c, data, 1) == 1) { + DBG("====%s %d Run OK=======\n", __func__, __LINE__); + rk1000_codec_write_reg_cache(codec, reg, value); return 0; - }else{ - DBG("================%s Run EIO=======%d=========\n",__FUNCTION__,__LINE__); + } else { + DBG("====%s %d Run EIO=====\n", __func__, __LINE__); return -EIO; - } + } } -static const struct snd_kcontrol_new rk1000_codec_snd_controls[] = { - -SOC_DOUBLE_R("Capture Volume", ACCELCODEC_R0C, ACCELCODEC_R0D, 0, 15, 0), -SOC_DOUBLE_R("Capture Switch", ACCELCODEC_R0C, ACCELCODEC_R0D, 7, 1, 1), - -SOC_DOUBLE_R("PCM Volume", ACCELCODEC_R0D, ACCELCODEC_R0E, 0, 7, 0), - -//SOC_SINGLE("Left ADC Capture Volume", ACCELCODEC_R17, 0, 63, 0), -//SOC_SINGLE("Right ADC Capture Volume", ACCELCODEC_R18, 0, 63, 0), - - -}; - - -/* Left Mixer */ -static const struct snd_kcontrol_new rk1000_codec_left_mixer_controls[] = { -SOC_DAPM_SINGLE("Playback Switch", ACCELCODEC_R15, 6, 1, 0), -SOC_DAPM_SINGLE("Left Bypass Switch", ACCELCODEC_R15, 2, 1, 0), +#ifdef CONFIG_MODEM_SOUND +static int rk1000_codec_write_incall(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u8 data[2]; + struct i2c_client *i2c; -}; + DBG("Enter::%s, %d, reg=0x%02X, value=0x%02X\n", + __func__, __LINE__, reg, value); + i2c = to_i2c_client(codec->dev); + data[0] = value & 0x00ff; + rk1000_codec_write_reg_cache(codec, reg, value); + i2c = (struct i2c_client *)codec->control_data; + i2c->addr = (i2c->addr & 0x60) | reg; + if (codec->hw_write(i2c, data, 1) == 1) + return 0; + else + return -EIO; +} -/* Right Mixer */ -static const struct snd_kcontrol_new rk1000_codec_right_mixer_controls[] = { -SOC_DAPM_SINGLE("Playback Switch", ACCELCODEC_R15, 7, 1, 0), -SOC_DAPM_SINGLE("Left Bypass Switch", ACCELCODEC_R15, 3, 1, 0), +void call_set_spk(int on) +{ + struct rk1000_codec_priv *rk1000_codec; -}; + if (!rk1000_codec_codec) + return; + rk1000_codec = snd_soc_codec_get_drvdata(rk1000codec_codec); + if (!rk1000_codec) + return; + switch (on) { + case 0: + /* modem exit call,codec disable loopback */ + DBG("%s modem exit call\n", __func__); + rk1000_codec_write_incall(rk1000_codec_codec, + ACCELCODEC_R0E, 0x80); + rk1000_codec->call_enable = 0; + break; + case 1: + /* modem calling,codec enable loopback, + * spk hp different volume */ + DBG("%s spk incalling\n", __func__); + rk1000_codec->call_enable = 1; + rk1000_codec_write_incall(rk1000_codec_codec, + ACCELCODEC_R0E, 0x00); + return; + case 2: + DBG("%s hp incalling\n", __func__); + rk1000_codec->call_enable = 1; + rk1000_codec_write_incall(rk1000_codec_codec, + ACCELCODEC_R0E, 0x00); + break; + case 3: + DBG("%s bt incalling\n", __func__); + rk1000_codec->call_enable = 1; + rk1000_codec_write_incall(rk1000_codec_codec, + ACCELCODEC_R0E, 0x00); + break; + } +} +#endif -static const struct snd_soc_dapm_widget rk1000_codec_dapm_widgets[] = { - SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, - &rk1000_codec_left_mixer_controls[0], - ARRAY_SIZE(rk1000_codec_left_mixer_controls)), - SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, - &rk1000_codec_right_mixer_controls[0], - ARRAY_SIZE(rk1000_codec_right_mixer_controls)), - - //SND_SOC_DAPM_PGA("Right Out 1", ACCELCODEC_R1E, 0, 0, NULL, 0), - //SND_SOC_DAPM_PGA("Left Out 1", ACCELCODEC_R1E, 1, 0, NULL, 0), - //SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ACCELCODEC_R1F, 1, 0), - //SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ACCELCODEC_R1F, 2, 0), - - SND_SOC_DAPM_ADC("ADC", "Capture", ACCELCODEC_R1D, 6, 1), - SND_SOC_DAPM_ADC("ADC BUFF", "Capture BUFF", ACCELCODEC_R1D, 2, 0), - - - SND_SOC_DAPM_OUTPUT("LOUT1"), - SND_SOC_DAPM_OUTPUT("ROUT1"), - - SND_SOC_DAPM_INPUT("LINPUT1"), - SND_SOC_DAPM_INPUT("RINPUT1"), -}; -static const struct snd_soc_dapm_route audio_map[] = { - /* left mixer */ - {"Left Mixer", "Playback Switch", "Left DAC"}, - {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, - {"Right Mixer", "Playback Switch", "Right DAC"}, - {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, - - /* left out 1 */ - {"Left Out 1", NULL, "Left Mixer"}, - {"LOUT1", NULL, "Left Out 1"}, - - - /* right out 1 */ - {"Right Out 1", NULL, "Right Mixer"}, - {"ROUT1", NULL, "Right Out 1"}, - - /* Left Line Mux */ - {"Left Line Mux", "Line 1", "LINPUT1"}, - {"Left Line Mux", "PGA", "Left PGA Mux"}, - {"Left Line Mux", "Differential", "Differential Mux"}, - - /* Right Line Mux */ - {"Right Line Mux", "Line 1", "RINPUT1"}, - {"Right Line Mux", "PGA", "Right PGA Mux"}, - {"Right Line Mux", "Differential", "Differential Mux"}, - - /* Left PGA Mux */ - {"Left PGA Mux", "Line 1", "LINPUT1"}, - {"Left PGA Mux", "Line 2", "LINPUT2"}, - {"Left PGA Mux", "Line 3", "LINPUT3"}, - {"Left PGA Mux", "Differential", "Differential Mux"}, - - /* Right PGA Mux */ - {"Right PGA Mux", "Line 1", "RINPUT1"}, - {"Right PGA Mux", "Differential", "Differential Mux"}, - - /* Differential Mux */ - {"Differential Mux", "Line 1", "LINPUT1"}, - {"Differential Mux", "Line 1", "RINPUT1"}, - - /* Left ADC Mux */ - {"Left ADC Mux", "Stereo", "Left PGA Mux"}, - {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, - {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, - - /* Right ADC Mux */ - {"Right ADC Mux", "Stereo", "Right PGA Mux"}, - {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, - {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, - - /* ADC */ - {"Left ADC", NULL, "Left ADC Mux"}, - {"Right ADC", NULL, "Right ADC Mux"}, - - /* terminator */ - {NULL, NULL, NULL}, -}; struct _coeff_div { u32 mclk; @@ -277,62 +285,52 @@ struct _coeff_div { /* codec hifi mclk clock divider coefficients */ static const struct _coeff_div coeff_div[] = { /* 8k */ - {12288000, 8000, 1536, 0x6, 0x0,ASC_BCLKDIV_16}, - {11289600, 8000, 1408, 0x16, 0x0,ASC_BCLKDIV_16}, - {18432000, 8000, 2304, 0x7, 0x0,ASC_BCLKDIV_16}, - {16934400, 8000, 2112, 0x17, 0x0,ASC_BCLKDIV_16}, - {8192000, 8000, 1024, 0x0, 0x0,ASC_BCLKDIV_16}, - {12000000, 8000, 1500, 0x6, 0x1,ASC_BCLKDIV_16}, - + {12288000, 8000, 1536, 0x6, 0x0, ASC_BCLKDIV_16}, + {11289600, 8000, 1408, 0x16, 0x0, ASC_BCLKDIV_16}, + {18432000, 8000, 2304, 0x7, 0x0, ASC_BCLKDIV_16}, + {16934400, 8000, 2112, 0x17, 0x0, ASC_BCLKDIV_16}, + {8192000, 8000, 1024, 0x0, 0x0, ASC_BCLKDIV_16}, + {12000000, 8000, 1500, 0x6, 0x1, ASC_BCLKDIV_16}, /* 11.025k */ - {11289600, 11025, 1024, 0x18, 0x0,ASC_BCLKDIV_16}, - {16934400, 11025, 1536, 0x19, 0x0,ASC_BCLKDIV_16}, - {12000000, 11025, 1088, 0x19, 0x1,ASC_BCLKDIV_16}, - - /* 12k */ - {12288000, 12000, 1024, 0x8, 0x0,ASC_BCLKDIV_16}, - {18432000, 12000, 1536, 0x9, 0x0,ASC_BCLKDIV_16}, - {12000000, 12000, 1000, 0x8, 0x1,ASC_BCLKDIV_16}, - + {11289600, 11025, 1024, 0x18, 0x0, ASC_BCLKDIV_16}, + {16934400, 11025, 1536, 0x19, 0x0, ASC_BCLKDIV_16}, + {12000000, 11025, 1088, 0x19, 0x1, ASC_BCLKDIV_16}, + /* 12k */ + {12288000, 12000, 1024, 0x8, 0x0, ASC_BCLKDIV_16}, + {18432000, 12000, 1536, 0x9, 0x0, ASC_BCLKDIV_16}, + {12000000, 12000, 1000, 0x8, 0x1, ASC_BCLKDIV_16}, /* 16k */ - {12288000, 16000, 768, 0xa, 0x0,ASC_BCLKDIV_8}, - {18432000, 16000, 1152, 0xb, 0x0,ASC_BCLKDIV_8}, - {12000000, 16000, 750, 0xa, 0x1,ASC_BCLKDIV_8}, - + {12288000, 16000, 768, 0xa, 0x0, ASC_BCLKDIV_8}, + {18432000, 16000, 1152, 0xb, 0x0, ASC_BCLKDIV_8}, + {12000000, 16000, 750, 0xa, 0x1, ASC_BCLKDIV_8}, /* 22.05k */ - {11289600, 22050, 512, 0x1a, 0x0,ASC_BCLKDIV_8}, - {16934400, 22050, 768, 0x1b, 0x0,ASC_BCLKDIV_8}, - {12000000, 22050, 544, 0x1b, 0x1,ASC_BCLKDIV_8}, - - /* 24k */ - {12288000, 24000, 512, 0x1c, 0x0,ASC_BCLKDIV_8}, - {18432000, 24000, 768, 0x1d, 0x0,ASC_BCLKDIV_8}, - {12000000, 24000, 500, 0x1c, 0x1,ASC_BCLKDIV_8}, - + {11289600, 22050, 512, 0x1a, 0x0, ASC_BCLKDIV_8}, + {16934400, 22050, 768, 0x1b, 0x0, ASC_BCLKDIV_8}, + {12000000, 22050, 544, 0x1b, 0x1, ASC_BCLKDIV_8}, + /* 24k */ + {12288000, 24000, 512, 0x1c, 0x0, ASC_BCLKDIV_8}, + {18432000, 24000, 768, 0x1d, 0x0, ASC_BCLKDIV_8}, + {12000000, 24000, 500, 0x1c, 0x1, ASC_BCLKDIV_8}, /* 32k */ - {12288000, 32000, 384, 0xc, 0x0,ASC_BCLKDIV_8}, - {18432000, 32000, 576, 0xd, 0x0,ASC_BCLKDIV_8}, - {12000000, 32000, 375, 0xa, 0x1,ASC_BCLKDIV_8}, - + {12288000, 32000, 384, 0xc, 0x0, ASC_BCLKDIV_8}, + {18432000, 32000, 576, 0xd, 0x0, ASC_BCLKDIV_8}, + {12000000, 32000, 375, 0xa, 0x1, ASC_BCLKDIV_8}, /* 44.1k */ - {11289600, 44100, 256, 0x10, 0x0,ASC_BCLKDIV_8}, - {16934400, 44100, 384, 0x11, 0x0,ASC_BCLKDIV_8}, - {12000000, 44100, 272, 0x11, 0x1,ASC_BCLKDIV_8}, - + {11289600, 44100, 256, 0x10, 0x0, ASC_BCLKDIV_4}, + {16934400, 44100, 384, 0x11, 0x0, ASC_BCLKDIV_8}, + {12000000, 44100, 272, 0x11, 0x1, ASC_BCLKDIV_8}, /* 48k */ - {12288000, 48000, 256, 0x0, 0x0,ASC_BCLKDIV_4}, - {18432000, 48000, 384, 0x1, 0x0,ASC_BCLKDIV_4}, - {12000000, 48000, 250, 0x0, 0x1,ASC_BCLKDIV_4}, - + {12288000, 48000, 256, 0x0, 0x0, ASC_BCLKDIV_4}, + {18432000, 48000, 384, 0x1, 0x0, ASC_BCLKDIV_4}, + {12000000, 48000, 250, 0x0, 0x1, ASC_BCLKDIV_4}, /* 88.2k */ - {11289600, 88200, 128, 0x1e, 0x0,ASC_BCLKDIV_4}, - {16934400, 88200, 192, 0x1f, 0x0,ASC_BCLKDIV_4}, - {12000000, 88200, 136, 0x1f, 0x1,ASC_BCLKDIV_4}, - + {11289600, 88200, 128, 0x1e, 0x0, ASC_BCLKDIV_4}, + {16934400, 88200, 192, 0x1f, 0x0, ASC_BCLKDIV_4}, + {12000000, 88200, 136, 0x1f, 0x1, ASC_BCLKDIV_4}, /* 96k */ - {12288000, 96000, 128, 0xe, 0x0,ASC_BCLKDIV_4}, - {18432000, 96000, 192, 0xf, 0x0,ASC_BCLKDIV_4}, - {12000000, 96000, 125, 0xe, 0x1,ASC_BCLKDIV_4}, + {12288000, 96000, 128, 0xe, 0x0, ASC_BCLKDIV_4}, + {18432000, 96000, 192, 0xf, 0x0, ASC_BCLKDIV_4}, + {12000000, 96000, 125, 0xe, 0x1, ASC_BCLKDIV_4}, }; static inline int get_coeff(int mclk, int rate) @@ -343,7 +341,6 @@ static inline int get_coeff(int mclk, int rate) if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) return i; } - return -EINVAL; } @@ -377,17 +374,50 @@ static struct snd_pcm_hw_constraint_list constraints_12 = { .list = rates_12, }; +static int rk1000_codec_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + DBG("Enter::%s----%d now_level =%d old_level = %d\n", + __func__, __LINE__, level, codec->dapm.bias_level); + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40); + rk1000_codec_write(codec, ACCELCODEC_R1F, 0x49); + /*VREF, VMID=2x50k, digital enabled */ + break; + + case SND_SOC_BIAS_STANDBY: + DBG("rk1000 standby\n"); + rk1000_codec_write(codec, ACCELCODEC_R1D, 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R1F, 0xFF); + break; + + case SND_SOC_BIAS_OFF: + DBG("rk1000 power off\n"); + spk_ctrl_fun(GPIO_LOW); + rk1000_codec_write(codec, ACCELCODEC_R1D, 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R1F, 0xFF); + break; + } + codec->dapm.bias_level = level; + return 0; +} /* * Note that this should be called from init rather than from hw_params. */ static int rk1000_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct rk1000_codec_priv *rk1000_codec = snd_soc_codec_get_drvdata(codec); - - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - freq = 12000000; + struct rk1000_codec_priv *rk1000_codec; + + DBG("Enter::%s----%d\n", __func__, __LINE__); + rk1000_codec = snd_soc_codec_get_drvdata(codec); switch (freq) { case 11289600: case 18432000: @@ -415,23 +445,27 @@ static int rk1000_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) + unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; + struct rk1000_codec_priv *rk1000_codec; u16 iface = 0; + rk1000_codec = snd_soc_codec_get_drvdata(codec); + /* setup Vmid and Vref, other module power down */ + rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: iface = 0x0040; break; case SND_SOC_DAIFMT_CBS_CFS: - iface = 0x0020; + iface = 0x0000; break; default: return -EINVAL; } - /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -451,7 +485,6 @@ static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -468,216 +501,122 @@ static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - - DBG("Enter::%s----%d iface=%x\n",__FUNCTION__,__LINE__,iface); + DBG("Enter::%s----%d iface=%x\n", __func__, __LINE__, iface); rk1000_codec_write(codec, ACCELCODEC_R09, iface); return 0; } -static int rk1000_codec_pcm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct rk1000_codec_priv *rk1000_codec = snd_soc_codec_get_drvdata(codec); - - /* The set of sample rates that can be supported depends on the - * MCLK supplied to the CODEC - enforce this. - */ - DBG("Enter::%s----%d rk1000_codec->sysclk=%d\n",__FUNCTION__,__LINE__,rk1000_codec->sysclk); -// if (!rk1000_codec->sysclk) { -// dev_err(codec->dev, -// "No MCLK configured, call set_sysclk() on init\n"); -// return -EINVAL; -// } - -#if 0 - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - rk1000_codec->sysclk_constraints); -#endif - return 0; -} + static int rk1000_codec_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct rk1000_codec_priv *rk1000_codec = snd_soc_codec_get_drvdata(codec); - - u16 iface = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R09) & 0x1f3; - u16 srate = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R00) & 0x180; + u16 iface; int coeff; - - rk1000_codec->sysclk = 12000000; - /*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) - { - u16 r17 = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R17); - u16 r18 = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R18); - - r17 &= (~0x3f); //6db - r18 &= (~0x3f); //6db - - rk1000_codec_write(codec, ACCELCODEC_R17, r17); - rk1000_codec_write(codec, ACCELCODEC_R18, r18); - - return 0; - } - else if (params->flags == HW_PARAMS_FLAG_EQVOL_OFF) - { - u16 r17 = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R17); - u16 r18 = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R18); - - r17 &= (~0x3f); - r17 |= 0x0f; //0db - - r18 &= (~0x3f); - r18 |= 0x0f; //0db - - rk1000_codec_write(codec, ACCELCODEC_R17, r17); - rk1000_codec_write(codec, ACCELCODEC_R18, r18); - return 0; - } - - coeff = get_coeff(rk1000_codec->sysclk, params_rate(params)); - - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0004; - break; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0008; - break; - case SNDRV_PCM_FORMAT_S32_LE: - iface |= 0x000c; - break; - } - DBG("Enter::%s----%d iface=%x srate =%x rate=%d\n",__FUNCTION__,__LINE__,iface,srate,params_rate(params)); - - rk1000_codec_write(codec,ACCELCODEC_R0C, 0x17); - rk1000_codec_write(codec,ACCELCODEC_R04, ASC_INT_MUTE_L|ASC_INT_MUTE_R|ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF); //soft mute - //±ØÐëÏȽ«clkºÍEN_INT¶¼disableµô£¬·ñÔòÇл»bclk·ÖƵֵ¿ÉÄܵ¼ÖÂcodecÄÚ²¿Ê±Ðò»ìÂÒµô£¬ - //±íÏÖ³öÀ´µÄÏÖÏóÊÇ£¬ÒÔºóµÄÒôÀÖ¶¼±ä³ÉÁËÔëÒô£¬¶øÇÒ¾ÍËã°ÑÊäÈëcodecµÄI2S_DATAOUT¶Ï¿ªÒ²Ò»Ñù³öÔëÒô - rk1000_codec_write(codec,ACCELCODEC_R0B, ASC_DEC_DISABLE|ASC_INT_DISABLE); //0x00 - + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + unsigned int dai_fmt; + + rtd = substream->private_data; + codec = rtd->codec; + dai_fmt = rtd->card->dai_link[0].dai_fmt; + iface = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R09) & 0x1f3; + coeff = 0; + rk1000_codec_write(codec, ACCELCODEC_R0C, 0x17); + rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_MUTE_L|ASC_INT_MUTE_R| + ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF); + rk1000_codec_write(codec, ACCELCODEC_R0B, + ASC_DEC_DISABLE|ASC_INT_DISABLE); /* set iface & srate */ + if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) + iface |= ASC_INVERT_BCLK; rk1000_codec_write(codec, ACCELCODEC_R09, iface); if (coeff >= 0) - { - // rk1000_codec_write(codec, ACCELCODEC_R0A, (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb|ASC_CLKNODIV|ASC_CLK_ENABLE); rk1000_codec_write(codec, ACCELCODEC_R0A, 0xa0); - // rk1000_codec_write(codec, ACCELCODEC_R00, srate|coeff_div[coeff].bclk); - } - rk1000_codec_write(codec,ACCELCODEC_R0B, gR0BReg); - + rk1000_codec_write(codec, ACCELCODEC_R0B, g_r0_b_reg); return 0; } -void PhaseOut(struct snd_soc_codec *codec,u32 nStep, u32 us) -{ - DBG("%s[%d]\n",__FUNCTION__,__LINE__); - rk1000_codec_write(codec,ACCELCODEC_R17, 0x00|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //AOL - rk1000_codec_write(codec,ACCELCODEC_R18, 0x00|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //AOR - udelay(us); -} -void PhaseIn(struct snd_soc_codec *codec,u32 nStep, u32 us) -{ - DBG("%s[%d]\n",__FUNCTION__,__LINE__); - rk1000_codec_write(codec,ACCELCODEC_R17, 0x00|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //AOL gVolReg|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //AOL - rk1000_codec_write(codec,ACCELCODEC_R18, 0x00|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //gVolReg|ASC_OUTPUT_ACTIVE|ASC_CROSSZERO_EN); //AOR - udelay(us); -} static int rk1000_codec_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; + struct rk1000_codec_priv *rk1000_codec; - DBG("Enter::%s----%d--mute=%d\n",__FUNCTION__,__LINE__,mute); - - if (mute) - { - PhaseOut(codec,1, 5000); - rk1000_codec_write(codec,ACCELCODEC_R19, 0xFF); //AOM - rk1000_codec_write(codec,ACCELCODEC_R04, ASC_INT_MUTE_L|ASC_INT_MUTE_R|ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF); //soft mute - } - else - { - rk1000_codec_write(codec,ACCELCODEC_R1D, 0x2a); //setup Vmid and Vref, other module power down - rk1000_codec_write(codec,ACCELCODEC_R1E, 0x40); ///|ASC_PDASDML_ENABLE); - rk1000_codec_write(codec,ACCELCODEC_R1F, 0x09|ASC_PDMIXM_ENABLE|ASC_PDPAM_ENABLE); ///|ASC_PDMICB_ENABLE|ASC_PDMIXM_ENABLE); - PhaseIn(codec,1, 5000); - // if(gCodecVol != 0) - { - rk1000_codec_write(codec,ACCELCODEC_R04, ASC_INT_ACTIVE_L|ASC_INT_ACTIVE_R|ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF); - } - rk1000_codec_write(codec,ACCELCODEC_R19, 0x7F); //AOM - #if 0 - /*disable speaker */ - rockchip_mux_api_set(SPK_IOMUX_PIN_NAME, SPK_IOMUX_PIN_DIR); - GPIOSetPinDirection(SPK_CTRL_PIN,GPIO_OUT); - GPIOSetPinLevel(SPK_CTRL_PIN,GPIO_HIGH); + DBG("Enter::%s----%d--mute=%d\n", __func__, __LINE__, mute); + rk1000_codec = snd_soc_codec_get_drvdata(codec); + if (mute) { + /* AOL */ + rk1000_codec_write(codec, ACCELCODEC_R17, 0xFF); + /* AOR */ + rk1000_codec_write(codec, ACCELCODEC_R18, 0xFF); + /* AOM */ + rk1000_codec_write(codec, ACCELCODEC_R19, 0xFF); + /* soft mute */ + rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_MUTE_L| + ASC_INT_MUTE_R | ASC_SIDETONE_L_OFF | + ASC_SIDETONE_R_OFF); + } else { + /* setup Vmid and Vref, other module power down */ + rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40); + /* AOL */ + rk1000_codec_write(codec, ACCELCODEC_R17, VOLUME_CODEC_PA | + ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN); + /* AOR */ + rk1000_codec_write(codec, ACCELCODEC_R18, VOLUME_CODEC_PA | + ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN); + rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_ACTIVE_L| + ASC_INT_ACTIVE_R | ASC_SIDETONE_L_OFF| + ASC_SIDETONE_R_OFF); + /* AOM */ + rk1000_codec_write(codec, ACCELCODEC_R19, 0x7F); + #if OUT_CAPLESS + rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09| + ASC_PDMIXM_ENABLE); + #else + rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09| + ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE); #endif } return 0; } -static int rk1000_codec_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static void rk1000_delayedwork_fun(struct work_struct *work) { - u16 pwr_reg = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R1D) & ~0x1c1; - DBG("Enter::%s----%d level =%d\n",__FUNCTION__,__LINE__,level); - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* VREF, VMID=2x50k, digital enabled */ - rk1000_codec_write(codec, ACCELCODEC_R1D, pwr_reg | 0x0080); - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - /* VREF, VMID=2x5k */ - rk1000_codec_write(codec, ACCELCODEC_R1D, pwr_reg | 0x0080); - - /* Charge caps */ - msleep(100); - } - - /* VREF, VMID=2*500k, digital stopped */ - rk1000_codec_write(codec, ACCELCODEC_R1D, pwr_reg | 0x0080); - break; + struct snd_soc_codec *codec; + struct rk1000_codec_priv *rk1000_codec; - case SND_SOC_BIAS_OFF: - rk1000_codec_write(codec, ACCELCODEC_R1D, 0x0000); - break; + DBG("--------%s----------\n", __func__); + codec = rk1000_codec_codec; + rk1000_codec = snd_soc_codec_get_drvdata(codec); + if (!rk1000_codec->boot_depop) { + #if OUT_CAPLESS + rk1000_codec_write(codec, ACCELCODEC_R1F, + 0x09 | ASC_PDMIXM_ENABLE); + #else + rk1000_codec_write(codec, ACCELCODEC_R1F, + 0x09 | ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE); + #endif } - codec->dapm.bias_level = level; - return 0; + spk_ctrl_fun(GPIO_HIGH); } -#define RK1000_CODEC_RATES SNDRV_PCM_RATE_8000_96000 -#define RK1000_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_ops rk1000_codec_ops = { - .startup = rk1000_codec_pcm_startup, .hw_params = rk1000_codec_pcm_hw_params, .set_fmt = rk1000_codec_set_dai_fmt, .set_sysclk = rk1000_codec_set_dai_sysclk, .digital_mute = rk1000_codec_mute, }; +#define RK1000_CODEC_RATES SNDRV_PCM_RATE_8000_96000 +#define RK1000_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver rk1000_codec_dai[] = { { .name = "rk1000_codec", @@ -700,212 +639,222 @@ static struct snd_soc_dai_driver rk1000_codec_dai[] = { } }; -static int rk1000_codec_suspend(struct snd_soc_codec *codec) -{ - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} -static int rk1000_codec_resume(struct snd_soc_codec *codec) +void rk1000_codec_reg_set(void) { - int i; - u8 data[2]; - struct i2c_client *i2c; - u16 *cache = codec->reg_cache; - - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - /* Sync reg_cache with the hardware */ - for (i = 0; i < RK1000_CODEC_NUM_REG; i++) { - data[0] = cache[i] & 0x00ff; - i2c = (struct i2c_client *)codec->control_data; - i2c->addr = (i2c->addr & 0x60)|i; - codec->hw_write(codec->control_data, data, 1); + struct snd_soc_codec *codec; + struct rk1000_codec_priv *rk1000_codec; + unsigned int digital_gain; + unsigned int mic_vol; + + mic_vol = VOLUME_INPUT; + codec = rk1000_codec_codec; + rk1000_codec = snd_soc_codec_get_drvdata(codec); + rk1000_codec_write(codec, ACCELCODEC_R1D, 0x30); + rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40); +#ifdef USE_LPF + /*Route R-LPF->R-Mixer, L-LPF->L-Mixer*/ + rk1000_codec_write(codec, ACCELCODEC_R15, 0xC1); +#else + /*Route RDAC->R-Mixer, LDAC->L->Mixer*/ + rk1000_codec_write(codec, ACCELCODEC_R15, 0x0C); +#endif + /*With Cap Output, VMID ramp up slow*/ + rk1000_codec_write(codec, ACCELCODEC_R1A, 0x14); + mdelay(10); + rk1000_codec_write(codec, ACCELCODEC_R0C, 0x10 | ASC_INPUT_VOL_0DB); + rk1000_codec_write(codec, ACCELCODEC_R0D, 0x10 | ASC_INPUT_VOL_0DB); +#ifdef USE_MIC_IN + if (mic_vol > 0x07) { + /*Select MIC input*/ + rk1000_codec_write(codec, ACCELCODEC_R12, + 0x4c | ASC_MIC_INPUT | ASC_MIC_BOOST_20DB); + mic_vol -= 0x07; + } else + /*Select MIC input*/ + rk1000_codec_write(codec, ACCELCODEC_R12, 0x4c | ASC_MIC_INPUT); + /*use default value*/ + rk1000_codec_write(codec, ACCELCODEC_R1C, ASC_DEM_ENABLE); +#else + /*Select Line input*/ + rk1000_codec_write(codec, ACCELCODEC_R12, 0x4c); +#endif + rk1000_codec_write(codec, ACCELCODEC_R0E, 0x10|mic_vol); + /*Diable route PGA->R/L Mixer, PGA gain 0db.*/ + rk1000_codec_write(codec, ACCELCODEC_R13, 0x05 | 0 << 3); + rk1000_codec_write(codec, ACCELCODEC_R14, 0x05 | 0 << 3); + /*2soft mute*/ + rk1000_codec_write(codec, ACCELCODEC_R04, + ASC_INT_MUTE_L | ASC_INT_MUTE_R | + ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF); + /*2set default SR and clk*/ + rk1000_codec_write(codec, ACCELCODEC_R0A, FREQ441KHZ | ASC_NORMAL_MODE | + (0x10 << 1) | ASC_CLKNODIV | ASC_CLK_ENABLE); + g_r0_a_reg = ASC_NORMAL_MODE | (0x10 << 1) | + ASC_CLKNODIV | ASC_CLK_DISABLE; + /*2Config audio interface*/ + rk1000_codec_write(codec, ACCELCODEC_R09, ASC_I2S_MODE | + ASC_16BIT_MODE | ASC_NORMAL_LRCLK | + ASC_LRSWAP_DISABLE | ASC_NORMAL_BCLK); + rk1000_codec_write(codec, ACCELCODEC_R00, ASC_HPF_ENABLE + | ASC_DSM_MODE_ENABLE | ASC_SCRAMBLE_ENABLE + | ASC_DITHER_ENABLE | ASC_BCLKDIV_4); + /*2volume,input,output*/ + digital_gain = VOLUME_OUTPUT; + if (rk1000_codec_read(codec, ACCELCODEC_R05) != 0x0f) { + rk1000_codec_write(codec, ACCELCODEC_R05, + (digital_gain >> 8) & 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R06, digital_gain & 0xFF); } + if (rk1000_codec_read(codec, ACCELCODEC_R07) != 0x0f) { + rk1000_codec_write(codec, ACCELCODEC_R07, + (digital_gain >> 8) & 0xFF); + rk1000_codec_write(codec, ACCELCODEC_R08, digital_gain & 0xFF); + } + rk1000_codec_write(codec, ACCELCODEC_R0B, + ASC_DEC_ENABLE | ASC_INT_ENABLE); + g_r0_b_reg = ASC_DEC_ENABLE | ASC_INT_ENABLE; + if (rk1000_codec->boot_depop) { + #if OUT_CAPLESS + rk1000_codec_write(codec, ACCELCODEC_R1F, + 0x09 | ASC_PDMIXM_ENABLE); + #else + rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09 | + ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE); + #endif + } + rk1000_codec_write(codec, ACCELCODEC_R17, VOLUME_CODEC_PA | + ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN); + rk1000_codec_write(codec, ACCELCODEC_R18, VOLUME_CODEC_PA | + ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN); + rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_ACTIVE_L | + ASC_INT_ACTIVE_R | ASC_SIDETONE_L_OFF | + ASC_SIDETONE_R_OFF); + rk1000_codec_write(codec, ACCELCODEC_R19, 0x7F); +} - rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +static int rk1000_codec_suspend(struct snd_soc_codec *codec) +{ + DBG("Enter::%s----%d\n", __func__, __LINE__); + spk_ctrl_fun(GPIO_LOW); return 0; } -static void rk1000_reg_init(struct snd_soc_codec *codec) +static int rk1000_codec_resume(struct snd_soc_codec *codec) { - rk1000_codec_write(codec,ACCELCODEC_R1D, 0x00); - rk1000_codec_write(codec,ACCELCODEC_R17, 0xFF); //AOL - rk1000_codec_write(codec,ACCELCODEC_R18, 0xFF); //AOR - rk1000_codec_write(codec,ACCELCODEC_R19, 0xFF); //AOM - - rk1000_codec_write(codec,ACCELCODEC_R1F, 0xDF); - mdelay(10); - rk1000_codec_write(codec,ACCELCODEC_R1F, 0x5F); - rk1000_codec_write(codec,ACCELCODEC_R19, 0x7F); //AOM - rk1000_codec_write(codec,ACCELCODEC_R15, 0xC1);//rk1000_codec_write(codec,ACCELCODEC_R15, 0xCD);//by Vincent Hsiung - rk1000_codec_write(codec,ACCELCODEC_R1A, 0x1C); - mdelay(100); - rk1000_codec_write(codec,ACCELCODEC_R1F, 0x09); - rk1000_codec_write(codec,ACCELCODEC_R1E, 0x00); - mdelay(10); - rk1000_codec_write(codec,ACCELCODEC_R1A, 0x14); - rk1000_codec_write(codec,ACCELCODEC_R1D, 0xFE); - rk1000_codec_write(codec,ACCELCODEC_R17, 0xBF); //AOL - rk1000_codec_write(codec,ACCELCODEC_R18, 0xBF); //AOR - rk1000_codec_write(codec,ACCELCODEC_R19, 0x7F); //AOM - rk1000_codec_write(codec,ACCELCODEC_R1F, 0xDF); - - //2soft mute - rk1000_codec_write(codec,ACCELCODEC_R04, ASC_INT_MUTE_L|ASC_INT_MUTE_R|ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF); //soft mute - - //2set default SR and clk - rk1000_codec_write(codec,ACCELCODEC_R0A, ASC_USB_MODE|FREQ48kHz|ASC_CLKNODIV|ASC_CLK_DISABLE); - gR0AReg = ASC_USB_MODE|FREQ48kHz|ASC_CLKNODIV|ASC_CLK_DISABLE; - //2Config audio interface - rk1000_codec_write(codec,ACCELCODEC_R09, ASC_I2S_MODE|ASC_16BIT_MODE|ASC_NORMAL_LRCLK|ASC_LRSWAP_DISABLE|ASC_MASTER_MODE|ASC_NORMAL_BCLK); - rk1000_codec_write(codec,ACCELCODEC_R00, ASC_HPF_ENABLE|ASC_DSM_MODE_DISABLE|ASC_SCRAMBLE_ENABLE|ASC_DITHER_ENABLE|ASC_BCLKDIV_8); //BCLK div 8 - //2volume,input,outpu - rk1000_codec_write(codec,ACCELCODEC_R05, 0x0e); - rk1000_codec_write(codec,ACCELCODEC_R06, 0x42); - rk1000_codec_write(codec,ACCELCODEC_R07, 0x0e); - rk1000_codec_write(codec,ACCELCODEC_R08, 0x42); - - rk1000_codec_write(codec,ACCELCODEC_R0C, 0x10|ASC_INPUT_VOL_0DB|ASC_INPUT_MUTE); //LIL - rk1000_codec_write(codec,ACCELCODEC_R0D, 0x10|ASC_INPUT_VOL_0DB); //LIR - rk1000_codec_write(codec,ACCELCODEC_R0E, 0x10|ASC_INPUT_VOL_0DB); //MIC - rk1000_codec_write(codec,ACCELCODEC_R12, 0x4c|ASC_MIC_INPUT|ASC_MIC_BOOST_20DB); //mic input and boost 20dB - rk1000_codec_write(codec,ACCELCODEC_R13, ASC_LPGAMX_DISABLE|ASC_ALMX_DISABLE|((LINE_2_MIXER_GAIN & 0x7) << 4)|0x0); - rk1000_codec_write(codec,ACCELCODEC_R14, ASC_RPGAMX_DISABLE|ASC_ARMX_DISABLE|((LINE_2_MIXER_GAIN & 0x7) << 4)|0x0); - gR1314Reg = ASC_RPGAMX_DISABLE|ASC_ARMX_DISABLE|((LINE_2_MIXER_GAIN & 0x7) << 4)|0x0; - - //2other - rk1000_codec_write(codec,ACCELCODEC_R0B, ASC_DEC_DISABLE|ASC_INT_DISABLE); //0x00 - gR0BReg = ASC_DEC_DISABLE|ASC_INT_DISABLE; - rk1000_codec_write(codec,ACCELCODEC_R15, \ - 0x01|ASC_RLPFMX_DISABLE|ASC_LLPFMX_DISABLE|ASC_LDAMX_DISABLE|ASC_RDAMX_DISABLE|ASC_LSCF_ACTIVE|ASC_RSCF_ACTIVE); //0x3c - rk1000_codec_write(codec,ACCELCODEC_R1B, 0x32); - rk1000_codec_write(codec,ACCELCODEC_R1C, ASC_DEM_ENABLE); ///0x00); //use default value - - //dac mode - rk1000_codec_write(codec,ACCELCODEC_R17, 0xBF); //AOL ÒôÁ¿×îµÍ - rk1000_codec_write(codec,ACCELCODEC_R18, 0xBF); //AOR - - //2power down useless module - rk1000_codec_write(codec,ACCELCODEC_R1D, 0x2a|ASC_PDSDL_ENABLE|ASC_PDBSTL_ENABLE|ASC_PDPGAL_ENABLE); //setup Vmid and Vref, other module power down - rk1000_codec_write(codec,ACCELCODEC_R1E, 0x40|ASC_PDASDML_ENABLE); - #if OUT_CAPLESS - rk1000_codec_write(codec,ACCELCODEC_R1F, 0x09|ASC_PDMICB_ENABLE|ASC_PDMIXM_ENABLE); - #else - rk1000_codec_write(codec,ACCELCODEC_R1F, 0x09|ASC_PDMICB_ENABLE|ASC_PDMIXM_ENABLE|ASC_PDPAM_ENABLE); - #endif - - //2other - rk1000_codec_write(codec,ACCELCODEC_R0B, ASC_DEC_DISABLE|ASC_INT_ENABLE); - gR0BReg = ASC_DEC_ENABLE|ASC_INT_ENABLE; //ASC_DEC_DISABLE|ASC_INT_ENABLE; - rk1000_codec_write(codec,ACCELCODEC_R15, 0xC1);//rk1000_codec_write(codec,ACCELCODEC_R15, 0xCD);//by Vincent Hsiung - rk1000_codec_write(codec,ACCELCODEC_R0C, 0x10|ASC_INPUT_VOL_0DB|ASC_INPUT_MUTE); //LIL - rk1000_codec_write(codec,ACCELCODEC_R0D, 0x10|ASC_INPUT_VOL_0DB); //LIR - rk1000_codec_write(codec,ACCELCODEC_R0E, 0x10|ASC_INPUT_VOL_0DB); //MIC - rk1000_codec_write(codec,ACCELCODEC_R12, 0x4c|ASC_MIC_INPUT|ASC_MIC_BOOST_20DB); //mic input and boost 20dB - rk1000_codec_write(codec,ACCELCODEC_R13, 0x00); - rk1000_codec_write(codec,ACCELCODEC_R14, 0x00); - gR1314Reg = 0x00; - rk1000_codec_write(codec,ACCELCODEC_R1C, ASC_DEM_ENABLE); //0x00); //use default value + spk_ctrl_fun(GPIO_HIGH); + return 0; } static int rk1000_codec_probe(struct snd_soc_codec *codec) { - struct rk1000_codec_priv *rk1000_codec_priv = snd_soc_codec_get_drvdata(codec); - - int ret = 0; - DBG("%s::%d\n",__FUNCTION__,__LINE__); + struct rk1000_codec_priv *rk1000_codec; + int ret; rk1000_codec_codec = codec; - - codec->control_data = rk1000_codec_priv->control_data; - - ret = snd_soc_codec_set_cache_io(codec, 8, 8, rk1000_codec_priv->control_type); + rk1000_codec = snd_soc_codec_get_drvdata(codec); + DBG("[%s] start\n", __func__); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, + rk1000_codec->control_type); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - - codec->reg_cache = kmemdup(rk1000_codec_reg, sizeof(rk1000_codec_reg), GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - rk1000_reg_init(codec); -// snd_soc_add_codec_controls(codec, rk1000_codec_snd_controls, -// ARRAY_SIZE(rk1000_codec_snd_controls)); -// snd_soc_dapm_new_controls(codec, rk1000_codec_dapm_widgets, -// ARRAY_SIZE(rk1000_codec_dapm_widgets)); -// snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - + /*For RK1000, i2c write&read method is special + *do not use system default method.*/ + codec->write = rk1000_codec_write; + codec->read = rk1000_codec_read; + codec->hw_write = (hw_write_t)i2c_master_send; + if (rk1000_codec_codec == NULL) { + dev_err(codec->dev, "Codec device not registered\n"); + return -ENODEV; + } + INIT_DELAYED_WORK(&rk1000_codec->rk1000_delayed_work, + rk1000_delayedwork_fun); + + if (rk1000_codec->spk_ctrl_io) { + ret = gpio_request(rk1000_codec->spk_ctrl_io, + "rk1000-spk-ctrl"); + if (ret) { + DBG("rk1000 codec request gpio fail!\n"); + return ret; + } + /*set hight disable codec lr output*/ + gpio_direction_output(rk1000_codec->spk_ctrl_io, + !rk1000_codec->flags); + gpio_set_value(rk1000_codec->spk_ctrl_io, + !rk1000_codec->flags); + } + rk1000_codec->call_enable = 0; + rk1000_codec->headset_status = HP_OUT; + rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + schedule_delayed_work(&rk1000_codec->rk1000_delayed_work, + msecs_to_jiffies(rk1000_codec->pa_enable_time)); + rk1000_codec_reg_set(); + DBG("rk1000_codec_probe ret=0x%x\n", ret); return ret; } static int rk1000_codec_remove(struct snd_soc_codec *codec) { - struct rk1000_codec_priv *rk1000_codec_priv = snd_soc_codec_get_drvdata(codec); - rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); - kfree(rk1000_codec_priv); return 0; } static struct snd_soc_codec_driver soc_codec_dev_rk1000_codec = { - .probe = rk1000_codec_probe, - .remove = rk1000_codec_remove, - .suspend = rk1000_codec_suspend, + .probe = rk1000_codec_probe, + .remove = rk1000_codec_remove, + .suspend = rk1000_codec_suspend, .resume = rk1000_codec_resume, .set_bias_level = rk1000_codec_set_bias_level, - .read = rk1000_codec_read, - .write = rk1000_codec_write, -// .readable_register = rk1000_codec_read_reg_cache, -// .writable_register = rk1000_codec_write_reg_cache, -// .volatile_register = wm8994_volatile, .reg_cache_size = ARRAY_SIZE(rk1000_codec_reg), - .reg_word_size = sizeof(u8), + .reg_word_size = sizeof(u16), .reg_cache_default = rk1000_codec_reg, }; -#ifdef RK1000_CODEC_PROC -static int rk1000_codec_proc_init(void); -#endif static int rk1000_codec_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct rk1000_codec_priv *rk1000_codec; + struct device_node *rk1000_np = i2c->dev.of_node; int ret; - DBG("%s::%d\n",__FUNCTION__,__LINE__); - rk1000_codec = kzalloc(sizeof(struct rk1000_codec_priv), GFP_KERNEL); + + DBG("%s::%d\n", __func__, __LINE__); + rk1000_codec = kmalloc(sizeof(*rk1000_codec), GFP_KERNEL); if (rk1000_codec == NULL) return -ENOMEM; - + rk1000_codec->spk_ctrl_io = of_get_named_gpio_flags(rk1000_np, + "spk_ctl_io", 0, &(rk1000_codec->flags)); + if (!gpio_is_valid(rk1000_codec->spk_ctrl_io)) { + DBG("invalid core_info->reset_gpio: %d\n", + rk1000_codec->spk_ctrl_io); + return -1; + } + of_property_read_u32(rk1000_np, "pa_enable_time", + &(rk1000_codec->pa_enable_time)); + of_property_read_u32(rk1000_np, "boot_depop", + &(rk1000_codec->boot_depop)); i2c_set_clientdata(i2c, rk1000_codec); rk1000_codec->control_type = SND_SOC_I2C; - rk1000_codec->control_data = i2c; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rk1000_codec, - rk1000_codec_dai, ARRAY_SIZE(rk1000_codec_dai)); + rk1000_codec_dai, + ARRAY_SIZE(rk1000_codec_dai)); if (ret < 0) kfree(rk1000_codec); - -#ifdef RK1000_CODEC_PROC - rk1000_codec_proc_init(); -#endif - return ret; } static int rk1000_codec_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + kfree(i2c_get_clientdata(client)); return 0; } static const struct i2c_device_id rk1000_codec_i2c_id[] = { - { "rk1000_i2c_codec", 0 }, + { "rk1000_codec", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rk1000_codec_i2c_id); @@ -913,7 +862,7 @@ MODULE_DEVICE_TABLE(i2c, rk1000_codec_i2c_id); /* corgi i2c codec control layer */ static struct i2c_driver rk1000_codec_i2c_driver = { .driver = { - .name = "RK1000_CODEC", + .name = "rk1000_codec", .owner = THIS_MODULE, }, .probe = rk1000_codec_i2c_probe, @@ -924,9 +873,15 @@ static struct i2c_driver rk1000_codec_i2c_driver = { static int __init rk1000_codec_modinit(void) { - DBG("%s::%d\n",__FUNCTION__,__LINE__); - return i2c_add_driver(&rk1000_codec_i2c_driver); + int ret; + + DBG("[%s] start\n", __func__); + ret = i2c_add_driver(&rk1000_codec_i2c_driver); + if (ret != 0) + pr_err("rk1000 codec: register I2C driver err=: %d\n", ret); + return ret; } +/* late_initcall(rk1000_codec_modinit); */ module_init(rk1000_codec_modinit); static void __exit rk1000_codec_exit(void) @@ -935,230 +890,136 @@ static void __exit rk1000_codec_exit(void) } module_exit(rk1000_codec_exit); + + #ifdef RK1000_CODEC_PROC +#include +#include + +static int debug_write_read; + void rk1000_codec_reg_read(void) { - struct snd_soc_codec *codec = rk1000_codec_codec; - int i; - unsigned int data; - - for (i=0; i<=0x1f; i++){ - data = rk1000_codec_read(codec, i); - printk("reg[0x%x]=0x%x\n",i,data); - } + struct snd_soc_codec *codec; + int i; + unsigned int data; + + codec = rk1000_codec_codec; + for (i = 0; i <= 0x1f; i++) { + data = rk1000_codec_read(codec, i); + pr_info("reg[0x%x]=0x%x\n", i, data); + } } -static ssize_t rk1000_codec_proc_write(struct file *file, const char __user *buffer, - unsigned long len, void *data) + +static ssize_t rk1000_codec_proc_write(struct file *file, + const char __user *buffer, + size_t len, loff_t *data) { - char *cookie_pot; + char *cookie_pot; char *p; - int reg; - int value; - - cookie_pot = (char *)vmalloc( len ); - if (!cookie_pot) - { + long reg; + long value; + int ret; + + cookie_pot = vmalloc(len); + if (!cookie_pot) { + pr_err("malloc cookie error for rk1000 codec proc debug\n"); return -ENOMEM; - } - else - { - if (copy_from_user( cookie_pot, buffer, len )) + } else { + if (copy_from_user(cookie_pot, buffer, len)) return -EFAULT; } - - switch(cookie_pot[0]) - { + switch (cookie_pot[0]) { case 'd': case 'D': - debug_write_read ++; + debug_write_read++; debug_write_read %= 2; - if(debug_write_read != 0) - printk("Debug read and write reg on\n"); - else - printk("Debug read and write reg off\n"); - break; + if (debug_write_read != 0) + pr_info("Debug read and write reg on\n"); + else + pr_info("Debug read and write reg off\n"); + break; case 'r': case 'R': - printk("Read reg debug\n"); - if(cookie_pot[1] ==':') - { + pr_info("Read reg debug\n"); + if (cookie_pot[1] == ':') { debug_write_read = 1; - strsep(&cookie_pot,":"); - while((p=strsep(&cookie_pot,","))) - { - reg = simple_strtol(p,NULL,16); - value = rk1000_codec_read(rk1000_codec_codec,reg); - printk("rk1000_codec_read:0x%04x = 0x%04x",reg,value); + strsep(&cookie_pot, ":"); + while ((p = strsep(&cookie_pot, ","))) { + ret = kstrtol((const char *)p, 0, ®); + if (ret < 0) { + pr_err("string to long error\n"); + return ret; + } + value = rk1000_codec_read(rk1000_codec_codec, + reg); + pr_info("rk1000_codec_read:0x%04lx = 0x%04lx", + reg, value); } debug_write_read = 0; - printk("\n"); - } - else - { - printk("Error Read reg debug.\n"); - printk("For example: echo 'r:22,23,24,25'>wm8994_ts\n"); + pr_info("\n"); + } else { + pr_info("Error Read reg debug.\n"); } break; case 'w': case 'W': - printk("Write reg debug\n"); - if(cookie_pot[1] ==':') - { + pr_info("Write reg debug\n"); + if (cookie_pot[1] == ':') { debug_write_read = 1; - strsep(&cookie_pot,":"); - while((p=strsep(&cookie_pot,"="))) - { - reg = simple_strtol(p,NULL,16); - p=strsep(&cookie_pot,","); - value = simple_strtol(p,NULL,16); - rk1000_codec_write(rk1000_codec_codec,reg,value); - printk("rk1000_codec_write:0x%04x = 0x%04x\n",reg,value); + strsep(&cookie_pot, ":"); + while ((p = strsep(&cookie_pot, "="))) { + ret = kstrtol(p, 0, ®); + if (ret < 0) { + pr_err("string to long error\n"); + return ret; + } + p = strsep(&cookie_pot, ","); + ret = kstrtol(p, 0, &value); + if (ret < 0) { + pr_err("string to long error\n"); + return ret; + } + rk1000_codec_write(rk1000_codec_codec, reg, + value); + pr_info("rk1000_codec_write:0x%04lx = 0x%04lx\n", + reg, value); } debug_write_read = 0; - printk("\n"); - } - else - { - printk("Error Write reg debug.\n"); - printk("For example: w:22=0,23=0,24=0,25=0\n"); + pr_info("\n"); + } else { + pr_info("Error Write reg debug.\n"); + pr_info("For example: w:22=0,23=0,24=0,25=0\n"); } break; - case 'p'://enable pa + case 'p': rk1000_codec_reg_read(); break; default: - printk("Help for rk1000_codec_ts .\n-->The Cmd list: \n"); - printk("-->'d&&D' Open or Off the debug\n"); - printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>rk1000_codec_ts\n"); - printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>rk1000_codec_ts\n"); + pr_info("Help for rk1000_codec_ts .\n-->The Cmd list:\n"); + pr_info("-->'d&&D' Open or Off the debug\n"); + pr_info("-->'r&&R' Read reg debug,Example:"); + pr_info("echo 'r:22,23,24,25'>rk1000_codec_ts\n"); + pr_info("-->'w&&W' Write reg debug,Example:"); + pr_info("echo 'w:22=0,23=0,24=0,25=0'>rk1000_codec_ts\n"); break; } - + vfree(cookie_pot); return len; } + + static const struct file_operations rk1000_codec_proc_fops = { - .owner = THIS_MODULE, - //.open = snd_mem_proc_open, - //.read = seq_read, -//#ifdef CONFIG_PCI -// .write = rk1000_codec_proc_write, -//#endif - //.llseek = seq_lseek, - //.release = single_release, + .owner = THIS_MODULE, + .write = rk1000_codec_proc_write, }; static int rk1000_codec_proc_init(void) { - struct proc_dir_entry *rk1000_codec_proc_entry; - rk1000_codec_proc_entry = create_proc_entry("driver/rk1000_codec", 0777, NULL); - if(rk1000_codec_proc_entry != NULL) - { - rk1000_codec_proc_entry->write_proc = rk1000_codec_proc_write; - return -1; - } - else - { - printk("create rk1000_codec proc error !\n"); - } - return 0; -} - -#endif - -#if 1 -int reg_send_data(struct i2c_client *client, const char start_reg, - const char *buf, int count, unsigned int scl_rate) -{ - int ret; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - char tx_buf[count + 1]; - - tx_buf[0] = start_reg; - memcpy(tx_buf+1, buf, count); - - msg.addr = client->addr; - msg.buf = tx_buf; - msg.len = count +1; - msg.flags = client->flags; - msg.scl_rate = scl_rate; - - ret = i2c_transfer(adap, &msg, 1); - - return ret; -} - -static int rk1000_control_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - char data[4] = {0x88, 0x0d, 0x22, 0x00}; -// reg[0x00] = 0x88, --> ADC_CON -// reg[0x01] = 0x0d, --> CODEC_CON -// reg[0x02] = 0x22, --> I2C_CON -// reg[0x03] = 0x00, --> TVE_CON - #ifdef CONFIG_SND_SOC_RK1000 - data[1] = 0x00; - #endif - - DBG("%s::%d\n",__FUNCTION__,__LINE__); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - { - dev_err(&client->dev, "i2c bus does not support the rk1000_control\n"); - return -EIO; - } - - msleep(50); - ret = reg_send_data(client, 0x00, data, 4, 100 * 1000); -#if 1 - printk("i2c write ret = 0x%x\n",ret); - memset(data,0,sizeof(data)); - ret = i2c_master_recv(client, data, 4); - //ret = i2c_master_reg8_recv(client, 0, data, (int)4, 20*1000); - printk("i2c read reg %x, %x, %x, %x ret=x%x\n",data[0],data[1],data[2],data[3],ret); -#endif - - if (ret > 0) - ret = 0; - - return ret; -} - -static int rk1000_control_remove(struct i2c_client *client) -{ + proc_create("rk1000_codec_reg", 0, + NULL, &rk1000_codec_proc_fops); return 0; } - -static const struct i2c_device_id rk1000_control_id[] = { - { "rk1000_control", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, rk1000_control_id); - -static struct i2c_driver rk1000_control_driver = { - .driver = { - .name = "rk1000_control", - }, - .probe = rk1000_control_probe, - .remove = rk1000_control_remove, - .id_table = rk1000_control_id, -}; - -static int __init rk1000_control_init(void) -{ - return i2c_add_driver(&rk1000_control_driver); -} - -static void __exit rk1000_control_exit(void) -{ - i2c_del_driver(&rk1000_control_driver); -} - -module_init(rk1000_control_init); -module_exit(rk1000_control_exit); - -MODULE_DESCRIPTION("ASoC RK1000 CODEC driver"); -MODULE_AUTHOR("lhh lhh@rock-chips.com"); -MODULE_LICENSE("GPL"); +late_initcall(rk1000_codec_proc_init); #endif diff --git a/sound/soc/codecs/rk1000_codec.h b/sound/soc/codecs/rk1000_codec.h index 817219903b8b..8340e90fc1d0 100755 --- a/sound/soc/codecs/rk1000_codec.h +++ b/sound/soc/codecs/rk1000_codec.h @@ -15,251 +15,312 @@ /* RK1000 register space */ -#define ACCELCODEC_R00 0x00 //ADC High Pass Filter / DSM -#define ACCELCODEC_R01 0x01 //DITHER power -#define ACCELCODEC_R02 0x02 //DITHER power -#define ACCELCODEC_R03 0x03 //DITHER power -#define ACCELCODEC_R04 0x04 //Soft mute / sidetone gain control -#define ACCELCODEC_R05 0x05 //Right interpolate filter volume control (MSB) -#define ACCELCODEC_R06 0x06 //Right interpolate filter volume control (LSB) -#define ACCELCODEC_R07 0x07 //Left interpolate filter volume control (MSB) -#define ACCELCODEC_R08 0x08 //Left interpolate filter volume control (LSB) -#define ACCELCODEC_R09 0x09 //Audio interface control -#define ACCELCODEC_R0A 0x0A //Sample Rate / CLK control -#define ACCELCODEC_R0B 0x0B //Decimation filter / Interpolate filter enable -#define ACCELCODEC_R0C 0x0C //LIN volume -#define ACCELCODEC_R0D 0x0D //LIP volume -#define ACCELCODEC_R0E 0x0E //AL volume -//#define ACCELCODEC_R0F 0x0F //RIN volume -//#define ACCELCODEC_R10 0x10 //RIP volume -//#define ACCELCODEC_R11 0x11 //AR volume -#define ACCELCODEC_R12 0x12 //Input volume -#define ACCELCODEC_R13 0x13 //Left out mix -#define ACCELCODEC_R14 0x14 //Right out mix -#define ACCELCODEC_R15 0x15 //LPF out mix / SCF -#define ACCELCODEC_R16 0x16 //SCF control -#define ACCELCODEC_R17 0x17 //LOUT (AOL) volume -#define ACCELCODEC_R18 0x18 //ROUT (AOR) volume -#define ACCELCODEC_R19 0x19 //MONOOUT (AOM) volume -#define ACCELCODEC_R1A 0x1A //MONOOUT / Reference control -#define ACCELCODEC_R1B 0x1B //Bias Current control -#define ACCELCODEC_R1C 0x1C //ADC control -#define ACCELCODEC_R1D 0x1D //Power Mrg 1 -#define ACCELCODEC_R1E 0x1E //Power Mrg 2 -#define ACCELCODEC_R1F 0x1F //Power Mrg 3 +/* ADC High Pass Filter / DSM */ +#define ACCELCODEC_R00 0x00 +/* DITHER power */ +#define ACCELCODEC_R01 0x01 +/* DITHER power */ +#define ACCELCODEC_R02 0x02 +/* DITHER power */ +#define ACCELCODEC_R03 0x03 +/* Soft mute / sidetone gain control */ +#define ACCELCODEC_R04 0x04 +/* Right interpolate filter volume control (MSB) */ +#define ACCELCODEC_R05 0x05 +/* Right interpolate filter volume control (LSB) */ +#define ACCELCODEC_R06 0x06 +/* Left interpolate filter volume control (MSB) */ +#define ACCELCODEC_R07 0x07 +/* Left interpolate filter volume control (LSB) */ +#define ACCELCODEC_R08 0x08 +/* Audio interface control */ +#define ACCELCODEC_R09 0x09 +/* Sample Rate / CLK control */ +#define ACCELCODEC_R0A 0x0A +/* Decimation filter / Interpolate filter enable */ +#define ACCELCODEC_R0B 0x0B +/* LIN volume */ +#define ACCELCODEC_R0C 0x0C +/* LIP volume */ +#define ACCELCODEC_R0D 0x0D +/* AL volume */ +#define ACCELCODEC_R0E 0x0E +/* Input volume */ +#define ACCELCODEC_R12 0x12 +/* Left out mix */ +#define ACCELCODEC_R13 0x13 +/* Right out mix */ +#define ACCELCODEC_R14 0x14 +/* LPF out mix / SCF */ +#define ACCELCODEC_R15 0x15 +/* SCF control */ +#define ACCELCODEC_R16 0x16 +/* LOUT (AOL) volume */ +#define ACCELCODEC_R17 0x17 +/* ROUT (AOR) volume */ +#define ACCELCODEC_R18 0x18 +/* MONOOUT (AOM) volume */ +#define ACCELCODEC_R19 0x19 +/* MONOOUT / Reference control */ +#define ACCELCODEC_R1A 0x1A +/* Bias Current control */ +#define ACCELCODEC_R1B 0x1B +/* ADC control */ +#define ACCELCODEC_R1C 0x1C +/* Power Mrg 1 */ +#define ACCELCODEC_R1D 0x1D +/* Power Mrg 2 */ +#define ACCELCODEC_R1E 0x1E +/* Power Mrg 3 */ +#define ACCELCODEC_R1F 0x1F #define RK1000_CACHE_REGNUM 0x1F -//ACCELCODEC_R00 -#define ASC_HPF_ENABLE (0x1) //high_pass filter -#define ASC_HPF_DISABLE (0x0) +/* ACCELCODEC_R00 */ +/* high_pass filter */ +#define ASC_HPF_ENABLE (0x1) +#define ASC_HPF_DISABLE (0x0) -#define ASC_DSM_MODE_ENABLE (0x1 << 1) -#define ASC_DSM_MODE_DISABLE (0x0 << 1) - -#define ASC_SCRAMBLE_ENABLE (0x1 << 2) -#define ASC_SCRAMBLE_DISABLE (0x0 << 2) - -#define ASC_DITHER_ENABLE (0x1 << 3) -#define ASC_DITHER_DISABLE (0x0 << 3) - -#define ASC_BCLKDIV_4 (0x1 << 4) -#define ASC_BCLKDIV_8 (0x2 << 4) -#define ASC_BCLKDIV_16 (0x3 << 4) - -//ACCECODEC_R04 -#define ASC_INT_MUTE_L (0x1) -#define ASC_INT_ACTIVE_L (0x0) -#define ASC_INT_MUTE_R (0x1 << 1) -#define ASC_INT_ACTIVE_R (0x0 << 1) - -#define ASC_SIDETONE_L_OFF (0x0 << 2) -#define ASC_SIDETONE_L_GAIN_MAX (0x1 << 2) -#define ASC_SIDETONE_R_OFF (0x0 << 5) -#define ASC_SIDETONE_R_GAIN_MAX (0x1 << 5) - - -//ACCELCODEC_R05 -#define ASC_INT_VOL_0DB (0x0) - - -//ACCELCODEC_R09 -#define ASC_DSP_MODE (0x3) -#define ASC_I2S_MODE (0x2) -#define ASC_LEFT_MODE (0x1) -//#define ASC_RIGHT_MODE (0x0) - -#define ASC_32BIT_MODE (0x3 << 2) -#define ASC_24BIT_MODE (0x2 << 2) -#define ASC_20BIT_MODE (0x1 << 2) -#define ASC_16BIT_MODE (0x0 << 2) - -#define ASC_INVERT_LRCLK (0x1 << 4) -#define ASC_NORMAL_LRCLK (0x0 << 4) - -#define ASC_LRSWAP_ENABLE (0x1 << 5) -#define ASC_LRSWAP_DISABLE (0x0 << 5) - -#define ASC_MASTER_MODE (0x1 << 6) -#define ASC_SLAVE_MODE (0x0 << 6) - -#define ASC_INVERT_BCLK (0x1 << 7) -#define ASC_NORMAL_BCLK (0x0 << 7) - -//ACCELCODEC_R0A -#define ASC_USB_MODE (0x1) -#define ASC_NORMAL_MODE (0x0) - -#define FREQ96kHz (0x0e << 1) -#define FREQ48kHz (0x00 << 1) -#define FREQ441kHz (0x11 << 1) -#define FREQ32kHz (0x0c << 1) -#define FREQ24kHz (0x1c << 1) -#define FREQ2205kHz (0x1B << 1) -#define FREQ16kHz (0x0a << 1) -#define FREQ12kHz (0x08 << 1) -#define FREQ11025kHz (0x19 << 1) -//#define FREQ9k6Hz 0x09 -#define FREQ8kHz (0x06<<1) - -#define ASC_CLKDIV2 (0x1 << 6) -#define ASC_CLKNODIV (0x0 << 6) - -#define ASC_CLK_ENABLE (0x1 << 7) -#define ASC_CLK_DISABLE (0x0 << 7) - -//ACCELCODEC_R0B -#define ASC_DEC_ENABLE (0x1) //decimation filter enable -#define ASC_DEC_DISABLE (0x0) -#define ASC_INT_ENABLE (0x1 << 1) //interpolate filter enable -#define ASC_INT_DISABLE (0x0 << 1) - -//Input -#define ASC_INPUT_MUTE (0x1 << 7) -#define ASC_INPUT_ACTIVE (0x0 << 7) -#define ASC_INPUT_VOL_0DB (0x0) - -//ACCELCODEC_R12 -#define ASC_LINE_INPUT (0) -#define ASC_MIC_INPUT (1 << 7) - -#define ASC_MIC_BOOST_0DB (0) -#define ASC_MIC_BOOST_20DB (1 << 5) - -//ACCELCODEC_R13 -#define ASC_LPGAMXVOL_0DB (0x5) -#define ASC_LPGAMX_ENABLE (0x1 << 3) //the left channel PGA output is directly fed into the left mixer -#define ASC_LPGAMX_DISABLE (0x0 << 3) -#define ASC_ALMXVOL_0DB (0x5 << 4) -#define ASC_ALMX_ENABLE (0x1 << 7) //the left second line input is directly fed into the left mixer -#define ASC_ALMX_DISABLE (0x0 << 7) - -//ACCELCODEC_R14 -#define ASC_RPGAMXVOL_0DB (0x5) -#define ASC_RPGAMX_ENABLE (0x1 << 3) //the right channel PGA output is directly fed into the right mixer -#define ASC_RPGAMX_DISABLE (0x0 << 3) -#define ASC_ARMXVOL_0DB (0x5 << 4) -#define ASC_ARMX_ENABLE (0x1 << 7) //)the right second line input is directly fed into the right mixer -#define ASC_ARMX_DISABLE (0x0 << 7) - -//ACCELCODEC_R15 -#define ASC_LDAMX_ENABLE (0x1 << 2) //the left differential signal from DAC is directly fed into the left mixer -#define ASC_LDAMX_DISABLE (0x0 << 2) -#define ASC_RDAMX_ENABLE (0x1 << 3) //the right differential signal from DAC is directly fed into the right mixer -#define ASC_RDAMX_DISABLE (0x0 << 3) -#define ASC_LSCF_MUTE (0x1 << 4) //the left channel LPF is mute -#define ASC_LSCF_ACTIVE (0x0 << 4) -#define ASC_RSCF_MUTE (0x1 << 5) //the right channel LPF is mute -#define ASC_RSCF_ACTIVE (0x0 << 5) -#define ASC_LLPFMX_ENABLE (0x1 << 6) //the left channel LPF output is fed into the left into the mixer -#define ASC_LLPFMX_DISABLE (0x0 << 6) -#define ASC_RLPFMX_ENABLE (0x1 << 7) //the right channel LPF output is fed into the right into the mixer. -#define ASC_RLPFMX_DISABLE (0x0 << 7) - -//ACCELCODEC_R17/R18 -#define ASC_OUTPUT_MUTE (0x1 << 6) -#define ASC_OUTPUT_ACTIVE (0x0 << 6) -#define ASC_CROSSZERO_EN (0x1 << 7) -#define ASC_OUTPUT_VOL_0DB (0x0F) -//ACCELCODEC_R19 -#define ASC_MONO_OUTPUT_MUTE (0x1 << 7) -#define ASC_MONO_OUTPUT_ACTIVE (0x0 << 7) -#define ASC_MONO_CROSSZERO_EN (0x1 << 6) - -//ACCELCODEC_R1A -#define ASC_VMDSCL_SLOWEST (0x0 << 2) -#define ASC_VMDSCL_SLOW (0x1 << 2) -#define ASC_VMDSCL_FAST (0x2 << 2) -#define ASC_VMDSCL_FASTEST (0x3 << 2) - -#define ASC_MICBIAS_09 (0x1 << 4) -#define ASC_MICBIAS_06 (0x0 << 4) - -#define ASC_L2M_ENABLE (0x1 << 5) //the right channel LPF output is fed to mono PA -#define ASC_L2M_DISABLE (0x0 << 5) -#define ASC_R2M_ENABLE (0x1 << 6) //the left channel LPF output is fed to mono PA -#define ASC_R2M_DISABLE (0x0 << 6) -#define ASC_CAPLESS_ENABLE (0x1 << 7) //the capless connection is enable -#define ASC_CAPLESS_DISABLE (0x0 << 7) - -//ACCELCODEC_R1C -#define ASC_DITH_0_DIV (0x0 << 3) //the amplitude setting of the ASDM dither(div=vdd/48) -#define ASC_DITH_2_DIV (0x1 << 3) -#define ASC_DITH_4_DIV (0x2 << 3) -#define ASC_DITH_8_DIV (0x3 << 3) - -#define ASC_DITH_ENABLE (0x1 << 5) //the ASDM dither is enabled -#define ASC_DITH_DISABLE (0x0 << 5) - -#define ASC_DEM_ENABLE (0x1 << 7) //the ASDM DEM is enabled -#define ASC_DEM_DISABLE (0x0 << 7) - -//ACCELCODEC_R1D -#define ASC_PDVMID_ENABLE (0x1) //the VMID reference is powered down. VMID is connected to GND -#define ASC_PDVMID_DISABLE (0x0) -#define ASC_PDSDL_ENABLE (0x1 << 2) //the PGA S2D buffer is power down -#define ASC_PDSDL_DISABLE (0x0 << 2) -#define ASC_PDBSTL_ENABLE (0x1 << 4) //the micphone input Op-Amp is power down -#define ASC_PDBSTL_DISABLE (0x0 << 4) -#define ASC_PDPGAL_ENABLE (0x1 << 6) //the PGA is power down -#define ASC_PDPGAL_DISABLE (0x0 << 6) -#define ASC_PDREF_ENABLE (0x1 << 7) //reference generator is power down -#define ASC_PDREF_DISABLE (0x0 << 7) - -//ACCELCODEC_R1E -#define ASC_PDPAR_ENABLE (0x1) //the right channel PA is power down -#define ASC_PDPAR_DISABLE (0x0) -#define ASC_PDPAL_ENABLE (0x1 << 1) //the left channel power amplifier is power down -#define ASC_PDPAL_DISABLE (0x0 << 1) -#define ASC_PDMIXR_ENABLE (0x1 << 2) //the right mixer is power down -#define ASC_PDMIXR_DISABLE (0x0 << 2) -#define ASC_PDMIXL_ENABLE (0x1 << 3) //the left mixer is power down -#define ASC_PDMIXL_DISABLE (0x0 << 3) -#define ASC_PDLPFR_ENABLE (0x1 << 4) //the right RC LPF is power down -#define ASC_PDLPFR_DISABLE (0x0 << 4) -#define ASC_PDLPFL_ENABLE (0x1 << 5) //the left channel RC LPF is power down -#define ASC_PDLPFL_DISABLE (0x0 << 5) -#define ASC_PDASDML_ENABLE (0x1 << 7) //the ASDM is power down -#define ASC_PDASDML_DISABLE (0x0 << 7) - -//ACCELCODEC_R1F -#define ASC_PDSCFR_ENABLE (0x1 << 1) //the right channel DAC is power down -#define ASC_PDSCFR_DISABLE (0x0 << 1) -#define ASC_PDSCFL_ENABLE (0x1 << 2) //the left channel DAC is power down -#define ASC_PDSCFL_DISABLE (0x0 << 2) -#define ASC_PDMICB_ENABLE (0x1 << 4) //the micbias is power down -#define ASC_PDMICB_DISABLE (0x0 << 4) -#define ASC_PDIB_ENABLE (0x1 << 5) //the left channel LPF is power down -#define ASC_PDIB_DISABLE (0x0 << 5) -#define ASC_PDMIXM_ENABLE (0x1 << 6) //the mon mixer is power down -#define ASC_PDMIXM_DISABLE (0x0 << 6) -#define ASC_PDPAM_ENABLE (0x1 << 7) //the mono PA is power down. -#define ASC_PDPAM_DISABLE (0x0 << 7) - -#define LINE_2_MIXER_GAIN (0x5) //left and right PA gain -#define RK1000_CODEC_NUM_REG 0x20 - -//extern struct snd_soc_dai rk1000_codec_dai; -//extern struct snd_soc_codec_device soc_codec_dev_rk1000_codec; +#define ASC_DSM_MODE_ENABLE (0x1 << 1) +#define ASC_DSM_MODE_DISABLE (0x0 << 1) + +#define ASC_SCRAMBLE_ENABLE (0x1 << 2) +#define ASC_SCRAMBLE_DISABLE (0x0 << 2) + +#define ASC_DITHER_ENABLE (0x1 << 3) +#define ASC_DITHER_DISABLE (0x0 << 3) + +#define ASC_BCLKDIV_4 (0x1 << 4) +#define ASC_BCLKDIV_8 (0x2 << 4) +#define ASC_BCLKDIV_16 (0x3 << 4) + +/* ACCECODEC_R04 */ +#define ASC_INT_MUTE_L (0x1) +#define ASC_INT_ACTIVE_L (0x0) +#define ASC_INT_MUTE_R (0x1 << 1) +#define ASC_INT_ACTIVE_R (0x0 << 1) + +#define ASC_SIDETONE_L_OFF (0x0 << 2) +#define ASC_SIDETONE_L_GAIN_MAX (0x1 << 2) +#define ASC_SIDETONE_R_OFF (0x0 << 5) +#define ASC_SIDETONE_R_GAIN_MAX (0x1 << 5) + + +/* ACCELCODEC_R05 */ +#define ASC_INT_VOL_0DB (0x0) + + +/* ACCELCODEC_R09 */ +#define ASC_DSP_MODE (0x3) +#define ASC_I2S_MODE (0x2) +#define ASC_LEFT_MODE (0x1) +#define ASC_RIGHT_MODE (0x0) + +#define ASC_32BIT_MODE (0x3 << 2) +#define ASC_24BIT_MODE (0x2 << 2) +#define ASC_20BIT_MODE (0x1 << 2) +#define ASC_16BIT_MODE (0x0 << 2) + +#define ASC_INVERT_LRCLK (0x1 << 4) +#define ASC_NORMAL_LRCLK (0x0 << 4) + +#define ASC_LRSWAP_ENABLE (0x1 << 5) +#define ASC_LRSWAP_DISABLE (0x0 << 5) + +#define ASC_MASTER_MODE (0x1 << 6) +#define ASC_SLAVE_MODE (0x0 << 6) + +#define ASC_INVERT_BCLK (0x1 << 7) +#define ASC_NORMAL_BCLK (0x0 << 7) + +/* ACCELCODEC_R0A */ +#define ASC_USB_MODE (0x1) +#define ASC_NORMAL_MODE (0x0) + +#define FREQ96kHz (0x0e << 1) +#define FREQ48kHz (0x00 << 1) +#define FREQ441kHz (0x11 << 1) +#define FREQ32kHz (0x0c << 1) +#define FREQ24kHz (0x1c << 1) +#define FREQ2205kHz (0x1B << 1) +#define FREQ16kHz (0x0a << 1) +#define FREQ12kHz (0x08 << 1) +#define FREQ11025kHz (0x19 << 1) +#define FREQ8kHz (0x06<<1) + +#define ASC_CLKDIV2 (0x1 << 6) +#define ASC_CLKNODIV (0x0 << 6) + +#define ASC_CLK_ENABLE (0x1 << 7) +#define ASC_CLK_DISABLE (0x0 << 7) + +/* ACCELCODEC_R0B */ +#define ASC_DEC_ENABLE (0x1) +#define ASC_DEC_DISABLE (0x0) +#define ASC_INT_ENABLE (0x1 << 1) +#define ASC_INT_DISABLE (0x0 << 1) + +#define ASC_INPUT_MUTE (0x1 << 7) +#define ASC_INPUT_ACTIVE (0x0 << 7) +#define ASC_INPUT_VOL_0DB (0x0) + +/* ACCELCODEC_R12 */ +#define ASC_LINE_INPUT (0) +#define ASC_MIC_INPUT (1 << 7) + +#define ASC_MIC_BOOST_0DB (0) +#define ASC_MIC_BOOST_20DB (1 << 5) + +/* ACCELCODEC_R13 */ +#define ASC_LPGAMXVOL_0DB (0x5) +/* the left channel PGA output is directly fed into the left mixer */ +#define ASC_LPGAMX_ENABLE (0x1 << 3) +#define ASC_LPGAMX_DISABLE (0x0 << 3) +#define ASC_ALMXVOL_0DB (0x5 << 4) +/* the left second line input is directly fed into the left mixer */ +#define ASC_ALMX_ENABLE (0x1 << 7) +#define ASC_ALMX_DISABLE (0x0 << 7) + +/* ACCELCODEC_R14 */ +#define ASC_RPGAMXVOL_0DB (0x5) +/* the right channel PGA output is directly fed into the right mixer */ +#define ASC_RPGAMX_ENABLE (0x1 << 3) +#define ASC_RPGAMX_DISABLE (0x0 << 3) +#define ASC_ARMXVOL_0DB (0x5 << 4) +/* the right second line input is directly fed into the right mixer */ +#define ASC_ARMX_ENABLE (0x1 << 7) +#define ASC_ARMX_DISABLE (0x0 << 7) + +/*ACCELCODEC_R15 */ +/*the left differential signal from DAC is directly fed into the left mixer*/ +#define ASC_LDAMX_ENABLE (0x1 << 2) +#define ASC_LDAMX_DISABLE (0x0 << 2) +/* the right differential signal from DAC is * +* directly fed into the right mixer */ +#define ASC_RDAMX_ENABLE (0x1 << 3) +#define ASC_RDAMX_DISABLE (0x0 << 3) +/* the left channel LPF is mute */ +#define ASC_LSCF_MUTE (0x1 << 4) +#define ASC_LSCF_ACTIVE (0x0 << 4) +/* the right channel LPF is mute */ +#define ASC_RSCF_MUTE (0x1 << 5) +#define ASC_RSCF_ACTIVE (0x0 << 5) +/* the left channel LPF output is fed into the left into the mixer */ +#define ASC_LLPFMX_ENABLE (0x1 << 6) +#define ASC_LLPFMX_DISABLE (0x0 << 6) +/* the right channel LPF output is fed into the right into the mixer. */ +#define ASC_RLPFMX_ENABLE (0x1 << 7) +#define ASC_RLPFMX_DISABLE (0x0 << 7) + +/* ACCELCODEC_R17/R18 */ +#define ASC_OUTPUT_MUTE (0x1 << 6) +#define ASC_OUTPUT_ACTIVE (0x0 << 6) +#define ASC_CROSSZERO_EN (0x1 << 7) +#define ASC_OUTPUT_VOL_0DB (0x0F) +/* ACCELCODEC_R19 */ +#define ASC_MONO_OUTPUT_MUTE (0x1 << 7) +#define ASC_MONO_OUTPUT_ACTIVE (0x0 << 7) +#define ASC_MONO_CROSSZERO_EN (0x1 << 6) + +/* ACCELCODEC_R1A */ +#define ASC_VMDSCL_SLOWEST (0x0 << 2) +#define ASC_VMDSCL_SLOW (0x1 << 2) +#define ASC_VMDSCL_FAST (0x2 << 2) +#define ASC_VMDSCL_FASTEST (0x3 << 2) + +#define ASC_MICBIAS_09 (0x1 << 4) +#define ASC_MICBIAS_06 (0x0 << 4) + +/* the right channel LPF output is fed to mono PA */ +#define ASC_L2M_ENABLE (0x1 << 5) +#define ASC_L2M_DISABLE (0x0 << 5) +/* the left channel LPF output is fed to mono PA */ +#define ASC_R2M_ENABLE (0x1 << 6) +#define ASC_R2M_DISABLE (0x0 << 6) +/* the capless connection is enable */ +#define ASC_CAPLESS_ENABLE (0x1 << 7) +#define ASC_CAPLESS_DISABLE (0x0 << 7) + +/* ACCELCODEC_R1C */ +/* the amplitude setting of the ASDM dither(div=vdd/48) */ +#define ASC_DITH_0_DIV (0x0 << 3) +#define ASC_DITH_2_DIV (0x1 << 3) +#define ASC_DITH_4_DIV (0x2 << 3) +#define ASC_DITH_8_DIV (0x3 << 3) + +/* the ASDM dither is enabled */ +#define ASC_DITH_ENABLE (0x1 << 5) +#define ASC_DITH_DISABLE (0x0 << 5) + +/* the ASDM DEM is enabled */ +#define ASC_DEM_ENABLE (0x1 << 7) +#define ASC_DEM_DISABLE (0x0 << 7) + +/* ACCELCODEC_R1D */ +/* the VMID reference is powered down. VMID is connected to GND */ +#define ASC_PDVMID_ENABLE (0x1) +#define ASC_PDVMID_DISABLE (0x0) +/* the PGA S2D buffer is power down */ +#define ASC_PDSDL_ENABLE (0x1 << 2) +#define ASC_PDSDL_DISABLE (0x0 << 2) +/* the micphone input Op-Amp is power down */ +#define ASC_PDBSTL_ENABLE (0x1 << 4) +#define ASC_PDBSTL_DISABLE (0x0 << 4) +/* the PGA is power down */ +#define ASC_PDPGAL_ENABLE (0x1 << 6) +#define ASC_PDPGAL_DISABLE (0x0 << 6) +/* reference generator is power down */ +#define ASC_PDREF_ENABLE (0x1 << 7) +#define ASC_PDREF_DISABLE (0x0 << 7) + +/* ACCELCODEC_R1E */ +/* the right channel PA is power down */ +#define ASC_PDPAR_ENABLE (0x1) +#define ASC_PDPAR_DISABLE (0x0) +/* the left channel power amplifier is power down */ +#define ASC_PDPAL_ENABLE (0x1 << 1) +#define ASC_PDPAL_DISABLE (0x0 << 1) +/* the right mixer is power down */ +#define ASC_PDMIXR_ENABLE (0x1 << 2) +#define ASC_PDMIXR_DISABLE (0x0 << 2) +/* the left mixer is power down */ +#define ASC_PDMIXL_ENABLE (0x1 << 3) +#define ASC_PDMIXL_DISABLE (0x0 << 3) +/* the right RC LPF is power down */ +#define ASC_PDLPFR_ENABLE (0x1 << 4) +#define ASC_PDLPFR_DISABLE (0x0 << 4) +/* the left channel RC LPF is power down */ +#define ASC_PDLPFL_ENABLE (0x1 << 5) +#define ASC_PDLPFL_DISABLE (0x0 << 5) +/* the ASDM is power down */ +#define ASC_PDASDML_ENABLE (0x1 << 7) +#define ASC_PDASDML_DISABLE (0x0 << 7) + +/* ACCELCODEC_R1F */ +/* the right channel DAC is power down */ +#define ASC_PDSCFR_ENABLE (0x1 << 1) +#define ASC_PDSCFR_DISABLE (0x0 << 1) +/* the left channel DAC is power down */ +#define ASC_PDSCFL_ENABLE (0x1 << 2) +#define ASC_PDSCFL_DISABLE (0x0 << 2) +/* the micbias is power down */ +#define ASC_PDMICB_ENABLE (0x1 << 4) +#define ASC_PDMICB_DISABLE (0x0 << 4) +/* the left channel LPF is power down */ +#define ASC_PDIB_ENABLE (0x1 << 5) +#define ASC_PDIB_DISABLE (0x0 << 5) +/* the mon mixer is power down */ +#define ASC_PDMIXM_ENABLE (0x1 << 6) +#define ASC_PDMIXM_DISABLE (0x0 << 6) +/* the mono PA is power down. */ +#define ASC_PDPAM_ENABLE (0x1 << 7) +#define ASC_PDPAM_DISABLE (0x0 << 7) + +/* left and right PA gain */ +#define LINE_2_MIXER_GAIN (0x5) +#define RK1000_CODEC_NUM_REG 0x20 + +#define GPIO_HIGH 1 +#define GPIO_LOW 0 #endif diff --git a/sound/soc/rockchip/rk_rk1000codec.c b/sound/soc/rockchip/rk_rk1000codec.c index f10384687ac2..55610210238f 100755 --- a/sound/soc/rockchip/rk_rk1000codec.c +++ b/sound/soc/rockchip/rk_rk1000codec.c @@ -10,7 +10,6 @@ * * */ - #include #include #include @@ -19,20 +18,21 @@ #include #include #include - #include "../codecs/rk1000_codec.h" #include "card_info.h" #include "rk_pcm.h" #include "rk_i2s.h" -#if 1 -#define DBG(x...) printk(KERN_INFO x) +#define RK1000_CARD_DBG 0 + +#if RK1000_CARD_DBG +#define DBG(x...) pr_info(x) #else #define DBG(x...) #endif static int rk29_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; @@ -40,22 +40,21 @@ static int rk29_hw_params(struct snd_pcm_substream *substream, unsigned int dai_fmt = rtd->dai_link->dai_fmt; int ret; - DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__); - + DBG("Enter::%s----%d\n", __func__, __LINE__); /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); if (ret < 0) { - printk("%s():failed to set the format for codec side\n", __FUNCTION__); + pr_err("%s():failed to set the format for codec side\n", + __func__); return ret; } - /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); if (ret < 0) { - printk("%s():failed to set the format for cpu side\n", __FUNCTION__); + pr_err("%s():failed to set the format for cpu side\n", + __func__); return ret; } - return 0; } @@ -93,17 +92,14 @@ static int rockchip_rk1000_audio_probe(struct platform_device *pdev) struct snd_soc_card *card = &rockchip_rk1000_snd_card; card->dev = &pdev->dev; - ret = rockchip_of_get_sound_card_info(card); if (ret) { - printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret); + pr_err("%s() get sound card info failed:%d\n", __func__, ret); return ret; } - ret = snd_soc_register_card(card); if (ret) - printk("%s() register card failed:%d\n", __FUNCTION__, ret); - + pr_err("%s() register card failed:%d\n", __func__, ret); return ret; } @@ -112,7 +108,6 @@ static int rockchip_rk1000_audio_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); snd_soc_unregister_card(card); - return 0; }