mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-25 05:04:23 +08:00
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
This commit is contained in:
commit
412665b461
@ -914,6 +914,10 @@ Matt Sealey <matt@genesi-usa.com>
|
||||
Bo Shen <voice.shen@atmel.com>
|
||||
at91sam9x5ek ARM926EJS (AT91SAM9G15,G25,G35,X25,X35 SoC)
|
||||
|
||||
Rajeshwari Shinde <rajeshwari.s@samsung.com>
|
||||
|
||||
snow ARM ARMV7 (EXYNOS5250 SoC)
|
||||
|
||||
Michal Simek <monstr@monstr.eu>
|
||||
|
||||
zynq ARM ARMV7 (Zynq SoC)
|
||||
|
@ -95,3 +95,48 @@ void set_dp_phy_ctrl(unsigned int enable)
|
||||
if (cpu_is_exynos5())
|
||||
exynos5_dp_phy_control(enable);
|
||||
}
|
||||
|
||||
static void exynos5_set_ps_hold_ctrl(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
(struct exynos5_power *)samsung_get_base_power();
|
||||
|
||||
/* Set PS-Hold high */
|
||||
setbits_le32(&power->ps_hold_control,
|
||||
EXYNOS_PS_HOLD_CONTROL_DATA_HIGH);
|
||||
}
|
||||
|
||||
void set_ps_hold_ctrl(void)
|
||||
{
|
||||
if (cpu_is_exynos5())
|
||||
exynos5_set_ps_hold_ctrl();
|
||||
}
|
||||
|
||||
|
||||
static void exynos5_set_xclkout(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
(struct exynos5_power *)samsung_get_base_power();
|
||||
|
||||
/* use xxti for xclk out */
|
||||
clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK,
|
||||
PMU_DEBUG_XXTI);
|
||||
}
|
||||
|
||||
void set_xclkout(void)
|
||||
{
|
||||
if (cpu_is_exynos5())
|
||||
exynos5_set_xclkout();
|
||||
}
|
||||
|
||||
/* Enables hardware tripping to power off the system when TMU fails */
|
||||
void set_hw_thermal_trip(void)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
struct exynos5_power *power =
|
||||
(struct exynos5_power *)samsung_get_base_power();
|
||||
|
||||
/* PS_HOLD_CONTROL register ENABLE_HW_TRIP bit*/
|
||||
setbits_le32(&power->ps_hold_control, POWER_ENABLE_HW_TRIP);
|
||||
}
|
||||
}
|
||||
|
@ -151,4 +151,9 @@
|
||||
};
|
||||
};
|
||||
|
||||
tmu@10060000 {
|
||||
compatible = "samsung,exynos-tmu";
|
||||
reg = <0x10060000 0x10000>;
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -857,6 +857,9 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable);
|
||||
|
||||
void set_usbhost_phy_ctrl(unsigned int enable);
|
||||
|
||||
/* Enables hardware tripping to power off the system when TMU fails */
|
||||
void set_hw_thermal_trip(void);
|
||||
|
||||
#define POWER_USB_HOST_PHY_CTRL_EN (1 << 0)
|
||||
#define POWER_USB_HOST_PHY_CTRL_DISABLE (0 << 0)
|
||||
|
||||
@ -864,4 +867,25 @@ void set_dp_phy_ctrl(unsigned int enable);
|
||||
|
||||
#define EXYNOS_DP_PHY_ENABLE (1 << 0)
|
||||
|
||||
#define EXYNOS_PS_HOLD_CONTROL_DATA_HIGH (1 << 8)
|
||||
#define POWER_ENABLE_HW_TRIP (1UL << 31)
|
||||
|
||||
/*
|
||||
* Set ps_hold data driving value high
|
||||
* This enables the machine to stay powered on
|
||||
* after the initial power-on condition goes away
|
||||
* (e.g. power button).
|
||||
*/
|
||||
void set_ps_hold_ctrl(void);
|
||||
|
||||
/* PMU_DEBUG bits [12:8] = 0x1000 selects XXTI clock source */
|
||||
#define PMU_DEBUG_XXTI 0x1000
|
||||
/* Mask bit[12:8] for xxti clock selection */
|
||||
#define PMU_DEBUG_CLKOUT_SEL_MASK 0x1f00
|
||||
|
||||
/*
|
||||
* Pmu debug is used for xclkout, enable xclkout with
|
||||
* source as XXTI
|
||||
*/
|
||||
void set_xclkout(void);
|
||||
#endif
|
||||
|
@ -78,11 +78,12 @@ struct spl_machine_param {
|
||||
*/
|
||||
u32 uboot_size;
|
||||
enum boot_mode boot_source; /* Boot device */
|
||||
enum mem_manuf mem_manuf; /* Memory Manufacturer */
|
||||
unsigned frequency_mhz; /* Frequency of memory in MHz */
|
||||
unsigned arm_freq_mhz; /* ARM Frequency in MHz */
|
||||
u32 serial_base; /* Serial base address */
|
||||
u32 i2c_base; /* i2c base address */
|
||||
u32 board_rev_gpios; /* Board revision GPIOs */
|
||||
enum mem_manuf mem_manuf; /* Memory Manufacturer */
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
|
58
arch/arm/include/asm/arch-exynos/tmu.h
Normal file
58
arch/arm/include/asm/arch-exynos/tmu.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
* Akshay Saraswat <akshay.s@samsung.com>
|
||||
*
|
||||
* EXYNOS - Thermal Management Unit
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_TMU_H
|
||||
#define __ASM_ARCH_TMU_H
|
||||
|
||||
struct exynos5_tmu_reg {
|
||||
unsigned triminfo;
|
||||
unsigned rsvd1;
|
||||
unsigned rsvd2;
|
||||
unsigned rsvd3;
|
||||
unsigned rsvd4;
|
||||
unsigned triminfo_control;
|
||||
unsigned rsvd5;
|
||||
unsigned rsvd6;
|
||||
unsigned tmu_control;
|
||||
unsigned rsvd7;
|
||||
unsigned tmu_status;
|
||||
unsigned sampling_internal;
|
||||
unsigned counter_value0;
|
||||
unsigned counter_value1;
|
||||
unsigned rsvd8;
|
||||
unsigned rsvd9;
|
||||
unsigned current_temp;
|
||||
unsigned rsvd10;
|
||||
unsigned rsvd11;
|
||||
unsigned rsvd12;
|
||||
unsigned threshold_temp_rise;
|
||||
unsigned threshold_temp_fall;
|
||||
unsigned rsvd13;
|
||||
unsigned rsvd14;
|
||||
unsigned past_temp3_0;
|
||||
unsigned past_temp7_4;
|
||||
unsigned past_temp11_8;
|
||||
unsigned past_temp15_12;
|
||||
unsigned inten;
|
||||
unsigned intstat;
|
||||
unsigned intclear;
|
||||
unsigned rsvd15;
|
||||
unsigned emul_con;
|
||||
};
|
||||
#endif /* __ASM_ARCH_TMU_H */
|
@ -66,4 +66,17 @@
|
||||
compatible = "maxim,max77686_pmic";
|
||||
};
|
||||
};
|
||||
|
||||
tmu@10060000 {
|
||||
samsung,min-temp = <25>;
|
||||
samsung,max-temp = <125>;
|
||||
samsung,start-warning = <95>;
|
||||
samsung,start-tripping = <105>;
|
||||
samsung,hw-tripping = <110>;
|
||||
samsung,efuse-min-value = <40>;
|
||||
samsung,efuse-value = <55>;
|
||||
samsung,efuse-max-value = <100>;
|
||||
samsung,slope = <274761730>;
|
||||
samsung,dc-value = <25>;
|
||||
};
|
||||
};
|
||||
|
58
board/samsung/dts/exynos5250-snow.dts
Normal file
58
board/samsung/dts/exynos5250-snow.dts
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SAMSUNG Snow board device tree source
|
||||
*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
/include/ ARCH_CPU_DTS
|
||||
|
||||
/ {
|
||||
model = "Google Snow";
|
||||
compatible = "google,snow", "samsung,exynos5250";
|
||||
|
||||
aliases {
|
||||
i2c0 = "/i2c@12c60000";
|
||||
i2c1 = "/i2c@12c70000";
|
||||
i2c2 = "/i2c@12c80000";
|
||||
i2c3 = "/i2c@12c90000";
|
||||
i2c4 = "/i2c@12ca0000";
|
||||
i2c5 = "/i2c@12cb0000";
|
||||
i2c6 = "/i2c@12cc0000";
|
||||
i2c7 = "/i2c@12cd0000";
|
||||
spi0 = "/spi@12d20000";
|
||||
spi1 = "/spi@12d30000";
|
||||
spi2 = "/spi@12d40000";
|
||||
spi3 = "/spi@131a0000";
|
||||
spi4 = "/spi@131b0000";
|
||||
};
|
||||
|
||||
sound@12d60000 {
|
||||
samsung,i2s-epll-clock-frequency = <192000000>;
|
||||
samsung,i2s-sampling-rate = <48000>;
|
||||
samsung,i2s-bits-per-sample = <16>;
|
||||
samsung,i2s-channels = <2>;
|
||||
samsung,i2s-lr-clk-framesize = <256>;
|
||||
samsung,i2s-bit-clk-framesize = <32>;
|
||||
samsung,codec-type = "max98095";
|
||||
};
|
||||
|
||||
i2c@12cd0000 {
|
||||
soundcodec@22 {
|
||||
reg = <0x22>;
|
||||
compatible = "maxim,max98095-codec";
|
||||
};
|
||||
};
|
||||
|
||||
i2c@12c60000 {
|
||||
pmic@9 {
|
||||
reg = <0x9>;
|
||||
compatible = "maxim,max77686_pmic";
|
||||
};
|
||||
};
|
||||
};
|
@ -23,6 +23,7 @@
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/io.h>
|
||||
#include <errno.h>
|
||||
#include <i2c.h>
|
||||
#include <lcd.h>
|
||||
#include <netdev.h>
|
||||
@ -35,9 +36,40 @@
|
||||
#include <asm/arch/sromc.h>
|
||||
#include <asm/arch/dp_info.h>
|
||||
#include <power/pmic.h>
|
||||
#include <power/max77686_pmic.h>
|
||||
#include <tmu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined CONFIG_EXYNOS_TMU
|
||||
/*
|
||||
* Boot Time Thermal Analysis for SoC temperature threshold breach
|
||||
*/
|
||||
static void boot_temp_check(void)
|
||||
{
|
||||
int temp;
|
||||
|
||||
switch (tmu_monitor(&temp)) {
|
||||
/* Status TRIPPED ans WARNING means corresponding threshold breach */
|
||||
case TMU_STATUS_TRIPPED:
|
||||
puts("EXYNOS_TMU: TRIPPING! Device power going down ...\n");
|
||||
set_ps_hold_ctrl();
|
||||
hang();
|
||||
break;
|
||||
case TMU_STATUS_WARNING:
|
||||
puts("EXYNOS_TMU: WARNING! Temperature very high\n");
|
||||
break;
|
||||
/*
|
||||
* TMU_STATUS_INIT means something is wrong with temperature sensing
|
||||
* and TMU status was changed back from NORMAL to INIT.
|
||||
*/
|
||||
case TMU_STATUS_INIT:
|
||||
default:
|
||||
debug("EXYNOS_TMU: Unknown TMU state\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_EXYNOS
|
||||
int board_usb_vbus_init(void)
|
||||
{
|
||||
@ -54,14 +86,38 @@ int board_usb_vbus_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOUND_MAX98095
|
||||
static void board_enable_audio_codec(void)
|
||||
{
|
||||
struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *)
|
||||
samsung_get_base_gpio_part1();
|
||||
|
||||
/* Enable MAX98095 Codec */
|
||||
s5p_gpio_direction_output(&gpio1->x1, 7, 1);
|
||||
s5p_gpio_set_pull(&gpio1->x1, 7, GPIO_PULL_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
int board_init(void)
|
||||
{
|
||||
gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL);
|
||||
|
||||
#if defined CONFIG_EXYNOS_TMU
|
||||
if (tmu_init(gd->fdt_blob) != TMU_STATUS_NORMAL) {
|
||||
debug("%s: Failed to init TMU\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
boot_temp_check();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXYNOS_SPI
|
||||
spi_init();
|
||||
#endif
|
||||
#ifdef CONFIG_USB_EHCI_EXYNOS
|
||||
board_usb_vbus_init();
|
||||
#endif
|
||||
#ifdef CONFIG_SOUND_MAX98095
|
||||
board_enable_audio_codec();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -80,12 +136,119 @@ int dram_init(void)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_POWER)
|
||||
static int pmic_reg_update(struct pmic *p, int reg, uint regval)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
ret = pmic_reg_read(p, reg, &val);
|
||||
if (ret) {
|
||||
debug("%s: PMIC %d register read failed\n", __func__, reg);
|
||||
return -1;
|
||||
}
|
||||
val |= regval;
|
||||
ret = pmic_reg_write(p, reg, val);
|
||||
if (ret) {
|
||||
debug("%s: PMIC %d register write failed\n", __func__, reg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int power_init_board(void)
|
||||
{
|
||||
struct pmic *p;
|
||||
|
||||
set_ps_hold_ctrl();
|
||||
|
||||
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
|
||||
|
||||
if (pmic_init(I2C_PMIC))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
p = pmic_get("MAX77686_PMIC");
|
||||
if (!p)
|
||||
return -ENODEV;
|
||||
|
||||
if (pmic_probe(p))
|
||||
return -1;
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN))
|
||||
return -1;
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT,
|
||||
MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V))
|
||||
return -1;
|
||||
|
||||
/* VDD_MIF */
|
||||
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT,
|
||||
MAX77686_BUCK1OUT_1V)) {
|
||||
debug("%s: PMIC %d register write failed\n", __func__,
|
||||
MAX77686_REG_PMIC_BUCK1OUT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL,
|
||||
MAX77686_BUCK1CTRL_EN))
|
||||
return -1;
|
||||
|
||||
/* VDD_ARM */
|
||||
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1,
|
||||
MAX77686_BUCK2DVS1_1_3V)) {
|
||||
debug("%s: PMIC %d register write failed\n", __func__,
|
||||
MAX77686_REG_PMIC_BUCK2DVS1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1,
|
||||
MAX77686_BUCK2CTRL_ON))
|
||||
return -1;
|
||||
|
||||
/* VDD_INT */
|
||||
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1,
|
||||
MAX77686_BUCK3DVS1_1_0125V)) {
|
||||
debug("%s: PMIC %d register write failed\n", __func__,
|
||||
MAX77686_REG_PMIC_BUCK3DVS1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL,
|
||||
MAX77686_BUCK3CTRL_ON))
|
||||
return -1;
|
||||
|
||||
/* VDD_G3D */
|
||||
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1,
|
||||
MAX77686_BUCK4DVS1_1_2V)) {
|
||||
debug("%s: PMIC %d register write failed\n", __func__,
|
||||
MAX77686_REG_PMIC_BUCK4DVS1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1,
|
||||
MAX77686_BUCK3CTRL_ON))
|
||||
return -1;
|
||||
|
||||
/* VDD_LDO2 */
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1,
|
||||
MAX77686_LD02CTRL1_1_5V | EN_LDO))
|
||||
return -1;
|
||||
|
||||
/* VDD_LDO3 */
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1,
|
||||
MAX77686_LD03CTRL1_1_8V | EN_LDO))
|
||||
return -1;
|
||||
|
||||
/* VDD_LDO5 */
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1,
|
||||
MAX77686_LD05CTRL1_1_8V | EN_LDO))
|
||||
return -1;
|
||||
|
||||
/* VDD_LDO10 */
|
||||
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1,
|
||||
MAX77686_LD10CTRL1_1_8V | EN_LDO))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -212,8 +375,17 @@ int board_eth_init(bd_t *bis)
|
||||
#ifdef CONFIG_DISPLAY_BOARDINFO
|
||||
int checkboard(void)
|
||||
{
|
||||
printf("\nBoard: SMDK5250\n");
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
const char *board_name;
|
||||
|
||||
board_name = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
|
||||
if (board_name == NULL)
|
||||
printf("\nUnknown Board\n");
|
||||
else
|
||||
printf("\nBoard: %s\n", board_name);
|
||||
#else
|
||||
printf("\nBoard: SMDK5250\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -298,6 +298,7 @@ s5p_goni arm armv7 goni samsung
|
||||
smdkc100 arm armv7 smdkc100 samsung s5pc1xx
|
||||
origen arm armv7 origen samsung exynos
|
||||
s5pc210_universal arm armv7 universal_c210 samsung exynos
|
||||
snow arm armv7 smdk5250 samsung exynos
|
||||
smdk5250 arm armv7 smdk5250 samsung exynos
|
||||
smdkv310 arm armv7 smdkv310 samsung exynos
|
||||
trats arm armv7 trats samsung exynos
|
||||
|
@ -27,7 +27,9 @@
|
||||
|
||||
#include <dtt.h>
|
||||
#include <i2c.h>
|
||||
#include <tmu.h>
|
||||
|
||||
#if defined CONFIG_DTT_SENSORS
|
||||
static unsigned long sensor_initialized;
|
||||
|
||||
static void _initialize_dtt(void)
|
||||
@ -59,9 +61,11 @@ void dtt_init(void)
|
||||
/* switch back to original I2C bus */
|
||||
I2C_SET_BUS(old_bus);
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
int dtt_i2c(void)
|
||||
{
|
||||
#if defined CONFIG_DTT_SENSORS
|
||||
int i;
|
||||
unsigned char sensors[] = CONFIG_DTT_SENSORS;
|
||||
int old_bus;
|
||||
@ -83,8 +87,34 @@ int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
|
||||
/* switch back to original I2C bus */
|
||||
I2C_SET_BUS(old_bus);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dtt_tmu(void)
|
||||
{
|
||||
#if defined CONFIG_TMU_CMD_DTT
|
||||
int cur_temp;
|
||||
|
||||
/* Sense and return latest thermal info */
|
||||
if (tmu_monitor(&cur_temp) == TMU_STATUS_INIT) {
|
||||
puts("TMU is in unknown state, temperature is invalid\n");
|
||||
return -1;
|
||||
}
|
||||
printf("Current temperature: %u degrees Celsius\n", cur_temp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_dtt(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= dtt_i2c();
|
||||
err |= dtt_tmu();
|
||||
|
||||
return err;
|
||||
} /* do_dtt() */
|
||||
|
||||
/***************************************************/
|
||||
|
44
doc/device-tree-bindings/exynos/tmu.txt
Normal file
44
doc/device-tree-bindings/exynos/tmu.txt
Normal file
@ -0,0 +1,44 @@
|
||||
Exynos Thermal management Unit
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be "samsung,exynos-tmu" for TMU
|
||||
- samsung,min-temp : Minimum temperature value (25 degree celsius)
|
||||
- Current temperature of SoC should be more than this value.
|
||||
- samsung,max-temp : Maximum temperature value (125 degree celsius)
|
||||
- Current temperature of SoC should be less than this value.
|
||||
- samsung,start-warning : Temperature at which TMU starts giving warning (degree celsius)
|
||||
- samsung,start-tripping : Temperature at which TMU shuts down the system (degree celsius)
|
||||
- samsung,hw-tripping : Temperature at which hardware tripping should happen
|
||||
in case TMU fails to power off (degree celsius)
|
||||
- samsung,efuse-min-value : SOC efuse min value (Constant 40)
|
||||
- efuse-value should be more than this value.
|
||||
- samsung,efuse-value : SOC actual efuse value (Literal value)
|
||||
- This is the data trimming info.
|
||||
- This value is used to calculate measuring error.
|
||||
- samsung,efuse-max-value : SoC max efuse value (Constant 100)
|
||||
- efuse-value should be less than this value.
|
||||
- samsung,slope : Default value 274761730 (Constant 0x1060_8802).
|
||||
- This is the default value for TMU_CONTROL register.
|
||||
- It sets the gain of amplifier to the positive-tc generator block.
|
||||
- It selects thermal tripping mode and enables thermal tripping.
|
||||
- samsung,dc-value : Measured data calibration value (Constant 25)
|
||||
- Used for tempearture calculation.
|
||||
- This is 25 because temperature measured is always above 25 degrees.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
tmu@10060000 {
|
||||
compatible = "samsung,exynos-tmu"
|
||||
samsung,min-temp = <25>;
|
||||
samsung,max-temp = <125>;
|
||||
samsung,start-warning = <95>;
|
||||
samsung,start-tripping = <105>;
|
||||
samsung,hw-tripping = <110>;
|
||||
samsung,efuse-min-value = <40>;
|
||||
samsung,efuse-value = <55>;
|
||||
samsung,efuse-max-value = <100>;
|
||||
samsung,slope = <274761730>;
|
||||
samsung,dc-value = <25>;
|
||||
};
|
@ -412,9 +412,11 @@ int sdhci_init(struct mmc *mmc)
|
||||
status = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
||||
}
|
||||
|
||||
/* Eable all state */
|
||||
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE);
|
||||
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE);
|
||||
/* Enable only interrupts served by the SD controller */
|
||||
sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK
|
||||
, SDHCI_INT_ENABLE);
|
||||
/* Mask all sdhci interrupt sources */
|
||||
sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libpower.o
|
||||
|
||||
COBJS-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
|
||||
COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o
|
||||
COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o
|
||||
COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o
|
||||
|
319
drivers/power/exynos-tmu.c
Normal file
319
drivers/power/exynos-tmu.c
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
* Akshay Saraswat <akshay.s@samsung.com>
|
||||
*
|
||||
* EXYNOS - Thermal Management Unit
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <tmu.h>
|
||||
#include <asm/arch/tmu.h>
|
||||
#include <asm/arch/power.h>
|
||||
|
||||
#define TRIMINFO_RELOAD 1
|
||||
#define CORE_EN 1
|
||||
#define THERM_TRIP_EN (1 << 12)
|
||||
|
||||
#define INTEN_RISE0 1
|
||||
#define INTEN_RISE1 (1 << 4)
|
||||
#define INTEN_RISE2 (1 << 8)
|
||||
#define INTEN_FALL0 (1 << 16)
|
||||
#define INTEN_FALL1 (1 << 20)
|
||||
#define INTEN_FALL2 (1 << 24)
|
||||
|
||||
#define TRIM_INFO_MASK 0xff
|
||||
|
||||
#define INTCLEAR_RISE0 1
|
||||
#define INTCLEAR_RISE1 (1 << 4)
|
||||
#define INTCLEAR_RISE2 (1 << 8)
|
||||
#define INTCLEAR_FALL0 (1 << 16)
|
||||
#define INTCLEAR_FALL1 (1 << 20)
|
||||
#define INTCLEAR_FALL2 (1 << 24)
|
||||
#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
|
||||
INTCLEAR_RISE2 | INTCLEAR_FALL0 | \
|
||||
INTCLEAR_FALL1 | INTCLEAR_FALL2)
|
||||
|
||||
/* Tmeperature threshold values for various thermal events */
|
||||
struct temperature_params {
|
||||
/* minimum value in temperature code range */
|
||||
unsigned int min_val;
|
||||
/* maximum value in temperature code range */
|
||||
unsigned int max_val;
|
||||
/* temperature threshold to start warning */
|
||||
unsigned int start_warning;
|
||||
/* temperature threshold CPU tripping */
|
||||
unsigned int start_tripping;
|
||||
/* temperature threshold for HW tripping */
|
||||
unsigned int hardware_tripping;
|
||||
};
|
||||
|
||||
/* Pre-defined values and thresholds for calibration of current temperature */
|
||||
struct tmu_data {
|
||||
/* pre-defined temperature thresholds */
|
||||
struct temperature_params ts;
|
||||
/* pre-defined efuse range minimum value */
|
||||
unsigned int efuse_min_value;
|
||||
/* pre-defined efuse value for temperature calibration */
|
||||
unsigned int efuse_value;
|
||||
/* pre-defined efuse range maximum value */
|
||||
unsigned int efuse_max_value;
|
||||
/* current temperature sensing slope */
|
||||
unsigned int slope;
|
||||
};
|
||||
|
||||
/* TMU device specific details and status */
|
||||
struct tmu_info {
|
||||
/* base Address for the TMU */
|
||||
unsigned tmu_base;
|
||||
/* pre-defined values for calibration and thresholds */
|
||||
struct tmu_data data;
|
||||
/* value required for triminfo_25 calibration */
|
||||
unsigned int te1;
|
||||
/* value required for triminfo_85 calibration */
|
||||
unsigned int te2;
|
||||
/* Value for measured data calibration */
|
||||
int dc_value;
|
||||
/* enum value indicating status of the TMU */
|
||||
int tmu_state;
|
||||
};
|
||||
|
||||
/* Global struct tmu_info variable to store init values */
|
||||
static struct tmu_info gbl_info;
|
||||
|
||||
/*
|
||||
* Get current temperature code from register,
|
||||
* then calculate and calibrate it's value
|
||||
* in degree celsius.
|
||||
*
|
||||
* @return current temperature of the chip as sensed by TMU
|
||||
*/
|
||||
static int get_cur_temp(struct tmu_info *info)
|
||||
{
|
||||
int cur_temp;
|
||||
struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base;
|
||||
|
||||
/*
|
||||
* Temperature code range between min 25 and max 125.
|
||||
* May run more than once for first call as initial sensing
|
||||
* has not yet happened.
|
||||
*/
|
||||
do {
|
||||
cur_temp = readl(®->current_temp) & 0xff;
|
||||
} while (cur_temp == 0 && info->tmu_state == TMU_STATUS_NORMAL);
|
||||
|
||||
/* Calibrate current temperature */
|
||||
cur_temp = cur_temp - info->te1 + info->dc_value;
|
||||
|
||||
return cur_temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitors status of the TMU device and exynos temperature
|
||||
*
|
||||
* @param temp pointer to the current temperature value
|
||||
* @return enum tmu_status_t value, code indicating event to execute
|
||||
*/
|
||||
enum tmu_status_t tmu_monitor(int *temp)
|
||||
{
|
||||
int cur_temp;
|
||||
struct tmu_data *data = &gbl_info.data;
|
||||
|
||||
if (gbl_info.tmu_state == TMU_STATUS_INIT)
|
||||
return TMU_STATUS_INIT;
|
||||
|
||||
/* Read current temperature of the SOC */
|
||||
cur_temp = get_cur_temp(&gbl_info);
|
||||
*temp = cur_temp;
|
||||
|
||||
/* Temperature code lies between min 25 and max 125 */
|
||||
if (cur_temp >= data->ts.start_tripping &&
|
||||
cur_temp <= data->ts.max_val) {
|
||||
return TMU_STATUS_TRIPPED;
|
||||
} else if (cur_temp >= data->ts.start_warning) {
|
||||
return TMU_STATUS_WARNING;
|
||||
} else if (cur_temp < data->ts.start_warning &&
|
||||
cur_temp >= data->ts.min_val) {
|
||||
return TMU_STATUS_NORMAL;
|
||||
} else {
|
||||
/* Temperature code does not lie between min 25 and max 125 */
|
||||
gbl_info.tmu_state = TMU_STATUS_INIT;
|
||||
debug("EXYNOS_TMU: Thermal reading failed\n");
|
||||
return TMU_STATUS_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get TMU specific pre-defined values from FDT
|
||||
*
|
||||
* @param info pointer to the tmu_info struct
|
||||
* @param blob FDT blob
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
|
||||
{
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
int node;
|
||||
int error = 0;
|
||||
|
||||
/* Get the node from FDT for TMU */
|
||||
node = fdtdec_next_compatible(blob, 0,
|
||||
COMPAT_SAMSUNG_EXYNOS_TMU);
|
||||
if (node < 0) {
|
||||
debug("EXYNOS_TMU: No node for tmu in device tree\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the pre-defined TMU specific values from FDT.
|
||||
* All of these are expected to be correct otherwise
|
||||
* miscalculation of register values in tmu_setup_parameters
|
||||
* may result in misleading current temperature.
|
||||
*/
|
||||
info->tmu_base = fdtdec_get_addr(blob, node, "reg");
|
||||
if (info->tmu_base == FDT_ADDR_T_NONE) {
|
||||
debug("%s: Missing tmu-base\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
info->data.ts.min_val = fdtdec_get_int(blob,
|
||||
node, "samsung,min-temp", -1);
|
||||
error |= info->data.ts.min_val;
|
||||
info->data.ts.max_val = fdtdec_get_int(blob,
|
||||
node, "samsung,max-temp", -1);
|
||||
error |= info->data.ts.max_val;
|
||||
info->data.ts.start_warning = fdtdec_get_int(blob,
|
||||
node, "samsung,start-warning", -1);
|
||||
error |= info->data.ts.start_warning;
|
||||
info->data.ts.start_tripping = fdtdec_get_int(blob,
|
||||
node, "samsung,start-tripping", -1);
|
||||
error |= info->data.ts.start_tripping;
|
||||
info->data.ts.hardware_tripping = fdtdec_get_int(blob,
|
||||
node, "samsung,hw-tripping", -1);
|
||||
error |= info->data.ts.hardware_tripping;
|
||||
info->data.efuse_min_value = fdtdec_get_int(blob,
|
||||
node, "samsung,efuse-min-value", -1);
|
||||
error |= info->data.efuse_min_value;
|
||||
info->data.efuse_value = fdtdec_get_int(blob,
|
||||
node, "samsung,efuse-value", -1);
|
||||
error |= info->data.efuse_value;
|
||||
info->data.efuse_max_value = fdtdec_get_int(blob,
|
||||
node, "samsung,efuse-max-value", -1);
|
||||
error |= info->data.efuse_max_value;
|
||||
info->data.slope = fdtdec_get_int(blob,
|
||||
node, "samsung,slope", -1);
|
||||
error |= info->data.slope;
|
||||
info->dc_value = fdtdec_get_int(blob,
|
||||
node, "samsung,dc-value", -1);
|
||||
error |= info->dc_value;
|
||||
|
||||
if (error == -1) {
|
||||
debug("fail to get tmu node properties\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calibrate and calculate threshold values and
|
||||
* enable interrupt levels
|
||||
*
|
||||
* @param info pointer to the tmu_info struct
|
||||
*/
|
||||
static void tmu_setup_parameters(struct tmu_info *info)
|
||||
{
|
||||
unsigned int te_code, con;
|
||||
unsigned int warning_code, trip_code, hwtrip_code;
|
||||
unsigned int cooling_temp;
|
||||
unsigned int rising_value;
|
||||
struct tmu_data *data = &info->data;
|
||||
struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base;
|
||||
|
||||
/* Must reload for reading efuse value from triminfo register */
|
||||
writel(TRIMINFO_RELOAD, ®->triminfo_control);
|
||||
|
||||
/* Get the compensation parameter */
|
||||
te_code = readl(®->triminfo);
|
||||
info->te1 = te_code & TRIM_INFO_MASK;
|
||||
info->te2 = ((te_code >> 8) & TRIM_INFO_MASK);
|
||||
|
||||
if ((data->efuse_min_value > info->te1) ||
|
||||
(info->te1 > data->efuse_max_value)
|
||||
|| (info->te2 != 0))
|
||||
info->te1 = data->efuse_value;
|
||||
|
||||
/* Get RISING & FALLING Threshold value */
|
||||
warning_code = data->ts.start_warning
|
||||
+ info->te1 - info->dc_value;
|
||||
trip_code = data->ts.start_tripping
|
||||
+ info->te1 - info->dc_value;
|
||||
hwtrip_code = data->ts.hardware_tripping
|
||||
+ info->te1 - info->dc_value;
|
||||
|
||||
cooling_temp = 0;
|
||||
|
||||
rising_value = ((warning_code << 8) |
|
||||
(trip_code << 16) |
|
||||
(hwtrip_code << 24));
|
||||
|
||||
/* Set interrupt level */
|
||||
writel(rising_value, ®->threshold_temp_rise);
|
||||
writel(cooling_temp, ®->threshold_temp_fall);
|
||||
|
||||
/*
|
||||
* Init TMU control tuning parameters
|
||||
* [28:24] VREF - Voltage reference
|
||||
* [15:13] THERM_TRIP_MODE - Tripping mode
|
||||
* [12] THERM_TRIP_EN - Thermal tripping enable
|
||||
* [11:8] BUF_SLOPE_SEL - Gain of amplifier
|
||||
* [6] THERM_TRIP_BY_TQ_EN - Tripping by TQ pin
|
||||
*/
|
||||
writel(data->slope, ®->tmu_control);
|
||||
|
||||
writel(INTCLEARALL, ®->intclear);
|
||||
|
||||
/* TMU core enable */
|
||||
con = readl(®->tmu_control);
|
||||
con |= THERM_TRIP_EN | CORE_EN;
|
||||
|
||||
writel(con, ®->tmu_control);
|
||||
|
||||
/* Enable HW thermal trip */
|
||||
set_hw_thermal_trip();
|
||||
|
||||
/* LEV1 LEV2 interrupt enable */
|
||||
writel(INTEN_RISE1 | INTEN_RISE2, ®->inten);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize TMU device
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
int tmu_init(const void *blob)
|
||||
{
|
||||
gbl_info.tmu_state = TMU_STATUS_INIT;
|
||||
if (get_tmu_fdt_values(&gbl_info, blob) < 0)
|
||||
goto ret;
|
||||
|
||||
tmu_setup_parameters(&gbl_info);
|
||||
gbl_info.tmu_state = TMU_STATUS_NORMAL;
|
||||
ret:
|
||||
|
||||
return gbl_info.tmu_state;
|
||||
}
|
@ -28,6 +28,7 @@ LIB := $(obj)libsound.o
|
||||
COBJS-$(CONFIG_SOUND) += sound.o
|
||||
COBJS-$(CONFIG_I2S) += samsung-i2s.o
|
||||
COBJS-$(CONFIG_SOUND_WM8994) += wm8994.o
|
||||
COBJS-$(CONFIG_SOUND_MAX98095) += max98095.o
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
SRCS := $(COBJS:.o=.c)
|
||||
|
550
drivers/sound/max98095.c
Normal file
550
drivers/sound/max98095.c
Normal file
@ -0,0 +1,550 @@
|
||||
/*
|
||||
* max98095.c -- MAX98095 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*
|
||||
* Modified for uboot by R. Chandrasekar (rcsekar@samsung.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <sound.h>
|
||||
#include "i2s.h"
|
||||
#include "max98095.h"
|
||||
|
||||
enum max98095_type {
|
||||
MAX98095,
|
||||
};
|
||||
|
||||
struct max98095_priv {
|
||||
enum max98095_type devtype;
|
||||
unsigned int sysclk;
|
||||
unsigned int rate;
|
||||
unsigned int fmt;
|
||||
};
|
||||
|
||||
static struct sound_codec_info g_codec_info;
|
||||
struct max98095_priv g_max98095_info;
|
||||
unsigned int g_max98095_i2c_dev_addr;
|
||||
|
||||
/* Index 0 is reserved. */
|
||||
int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
|
||||
88200, 96000};
|
||||
|
||||
/*
|
||||
* Writes value to a device register through i2c
|
||||
*
|
||||
* @param reg reg number to be write
|
||||
* @param data data to be writen to the above registor
|
||||
*
|
||||
* @return int value 1 for change, 0 for no change or negative error code.
|
||||
*/
|
||||
static int max98095_i2c_write(unsigned int reg, unsigned char data)
|
||||
{
|
||||
debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
|
||||
__func__, reg, data);
|
||||
return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a value from a device register through i2c
|
||||
*
|
||||
* @param reg reg number to be read
|
||||
* @param data address of read data to be stored
|
||||
*
|
||||
* @return int value 0 for success, -1 in case of error.
|
||||
*/
|
||||
static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1);
|
||||
if (ret != 0) {
|
||||
debug("%s: Error while reading register %#04x\n",
|
||||
__func__, reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* update device register bits through i2c
|
||||
*
|
||||
* @param reg codec register
|
||||
* @param mask register mask
|
||||
* @param value new value
|
||||
*
|
||||
* @return int value 0 for success, non-zero error code.
|
||||
*/
|
||||
static int max98095_update_bits(unsigned int reg, unsigned char mask,
|
||||
unsigned char value)
|
||||
{
|
||||
int change, ret = 0;
|
||||
unsigned char old, new;
|
||||
|
||||
if (max98095_i2c_read(reg, &old) != 0)
|
||||
return -1;
|
||||
new = (old & ~mask) | (value & mask);
|
||||
change = (old != new) ? 1 : 0;
|
||||
if (change)
|
||||
ret = max98095_i2c_write(reg, new);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
/*
|
||||
* codec mclk clock divider coefficients based on sampling rate
|
||||
*
|
||||
* @param rate sampling rate
|
||||
* @param value address of indexvalue to be stored
|
||||
*
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int rate_value(int rate, u8 *value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(rate_table); i++) {
|
||||
if (rate_table[i] >= rate) {
|
||||
*value = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*value = 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets hw params for max98095
|
||||
*
|
||||
* @param max98095 max98095 information pointer
|
||||
* @param rate Sampling rate
|
||||
* @param bits_per_sample Bits per sample
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
*/
|
||||
static int max98095_hw_params(struct max98095_priv *max98095,
|
||||
unsigned int rate, unsigned int bits_per_sample)
|
||||
{
|
||||
u8 regval;
|
||||
int error;
|
||||
|
||||
switch (bits_per_sample) {
|
||||
case 16:
|
||||
error = max98095_update_bits(M98095_034_DAI2_FORMAT,
|
||||
M98095_DAI_WS, 0);
|
||||
break;
|
||||
case 24:
|
||||
error = max98095_update_bits(M98095_034_DAI2_FORMAT,
|
||||
M98095_DAI_WS, M98095_DAI_WS);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Illegal bits per sample %d.\n",
|
||||
__func__, bits_per_sample);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rate_value(rate, ®val)) {
|
||||
debug("%s: Failed to set sample rate to %d.\n",
|
||||
__func__, rate);
|
||||
return -1;
|
||||
}
|
||||
max98095->rate = rate;
|
||||
|
||||
error |= max98095_update_bits(M98095_031_DAI2_CLKMODE,
|
||||
M98095_CLKMODE_MASK, regval);
|
||||
|
||||
/* Update sample rate mode */
|
||||
if (rate < 50000)
|
||||
error |= max98095_update_bits(M98095_038_DAI2_FILTERS,
|
||||
M98095_DAI_DHF, 0);
|
||||
else
|
||||
error |= max98095_update_bits(M98095_038_DAI2_FILTERS,
|
||||
M98095_DAI_DHF, M98095_DAI_DHF);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting hardware params.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures Audio interface system clock for the given frequency
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
* @param freq Sampling frequency in Hz
|
||||
*
|
||||
* @return -1 for error and 0 success.
|
||||
*/
|
||||
static int max98095_set_sysclk(struct max98095_priv *max98095,
|
||||
unsigned int freq)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Requested clock frequency is already setup */
|
||||
if (freq == max98095->sysclk)
|
||||
return 0;
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
|
||||
* 0x02 (when master clk is 20MHz to 40MHz)..
|
||||
* 0x03 (when master clk is 40MHz to 60MHz)..
|
||||
*/
|
||||
if ((freq >= 10000000) && (freq < 20000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
|
||||
} else if ((freq >= 20000000) && (freq < 40000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
|
||||
} else if ((freq >= 40000000) && (freq < 60000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
|
||||
} else {
|
||||
debug("%s: Invalid master clock frequency\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("%s: Clock at %uHz\n", __func__, freq);
|
||||
|
||||
if (error < 0)
|
||||
return -1;
|
||||
|
||||
max98095->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets Max98095 I2S format
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
* @param fmt i2S format - supports a subset of the options defined
|
||||
* in i2s.h.
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
*/
|
||||
static int max98095_set_fmt(struct max98095_priv *max98095, int fmt)
|
||||
{
|
||||
u8 regval = 0;
|
||||
int error = 0;
|
||||
|
||||
if (fmt == max98095->fmt)
|
||||
return 0;
|
||||
|
||||
max98095->fmt = fmt;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
/* Slave mode PLL */
|
||||
error |= max98095_i2c_write(M98095_032_DAI2_CLKCFG_HI,
|
||||
0x80);
|
||||
error |= max98095_i2c_write(M98095_033_DAI2_CLKCFG_LO,
|
||||
0x00);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* Set to master mode */
|
||||
regval |= M98095_DAI_MAS;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
default:
|
||||
debug("%s: Clock mode unsupported\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
regval |= M98095_DAI_DLY;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unrecognized format.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
regval |= M98095_DAI_WCI;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
regval |= M98095_DAI_BCI;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
regval |= M98095_DAI_BCI | M98095_DAI_WCI;
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unrecognized inversion settings.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
error |= max98095_update_bits(M98095_034_DAI2_FORMAT,
|
||||
M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
|
||||
M98095_DAI_WCI, regval);
|
||||
|
||||
error |= max98095_i2c_write(M98095_035_DAI2_CLOCK,
|
||||
M98095_DAI_BSEL64);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting i2s format.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* resets the audio codec
|
||||
*
|
||||
* @return -1 for error and 0 success.
|
||||
*/
|
||||
static int max98095_reset(void)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Gracefully reset the DSP core and the codec hardware in a proper
|
||||
* sequence.
|
||||
*/
|
||||
ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
|
||||
if (ret != 0) {
|
||||
debug("%s: Failed to reset DSP: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_i2c_write(M98095_097_PWR_SYS, 0);
|
||||
if (ret != 0) {
|
||||
debug("%s: Failed to reset codec: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset to hardware default for registers, as there is not a soft
|
||||
* reset hardware control register.
|
||||
*/
|
||||
for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
|
||||
ret = max98095_i2c_write(i, 0);
|
||||
if (ret < 0) {
|
||||
debug("%s: Failed to reset: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Intialise max98095 codec device
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
*
|
||||
* @returns -1 for error and 0 Success.
|
||||
*/
|
||||
static int max98095_device_init(struct max98095_priv *max98095)
|
||||
{
|
||||
unsigned char id;
|
||||
int error = 0;
|
||||
|
||||
/* reset the codec, the DSP core, and disable all interrupts */
|
||||
error = max98095_reset();
|
||||
if (error != 0) {
|
||||
debug("Reset\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* initialize private data */
|
||||
max98095->sysclk = -1U;
|
||||
max98095->rate = -1U;
|
||||
max98095->fmt = -1U;
|
||||
|
||||
error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
|
||||
if (error < 0) {
|
||||
debug("%s: Failure reading hardware revision: %d\n",
|
||||
__func__, id);
|
||||
goto err_access;
|
||||
}
|
||||
debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
|
||||
|
||||
error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
|
||||
|
||||
/*
|
||||
* initialize registers to hardware default configuring audio
|
||||
* interface2 to DAC
|
||||
*/
|
||||
error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
|
||||
M98095_DAI2M_TO_DACL|M98095_DAI2M_TO_DACR);
|
||||
|
||||
error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
|
||||
M98095_SPK_SPREADSPECTRUM);
|
||||
error |= max98095_i2c_write(M98095_045_CFG_DSP, M98095_DSPNORMAL);
|
||||
error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
|
||||
|
||||
error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
|
||||
M98095_S1NORMAL|M98095_SDATA);
|
||||
|
||||
error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
|
||||
M98095_S2NORMAL|M98095_SDATA);
|
||||
|
||||
error |= max98095_i2c_write(M98095_040_DAI3_IOCFG,
|
||||
M98095_S3NORMAL|M98095_SDATA);
|
||||
|
||||
/* take the codec out of the shut down */
|
||||
error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN,
|
||||
M98095_SHDNRUN);
|
||||
/* route DACL and DACR output to HO and Spekers */
|
||||
error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */
|
||||
error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */
|
||||
error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01); /* DACL */
|
||||
error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */
|
||||
|
||||
/* power Enable */
|
||||
error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
|
||||
|
||||
/* set Volume */
|
||||
error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15);
|
||||
error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15);
|
||||
error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16);
|
||||
error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16);
|
||||
|
||||
/* Enable DAIs */
|
||||
error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
|
||||
error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
|
||||
|
||||
err_access:
|
||||
if (error < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98095_do_init(struct sound_codec_info *pcodec_info,
|
||||
int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Enable codec clock */
|
||||
set_xclkout();
|
||||
|
||||
/* shift the device address by 1 for 7 bit addressing */
|
||||
g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
|
||||
|
||||
if (pcodec_info->codec_type == CODEC_MAX_98095)
|
||||
g_max98095_info.devtype = MAX98095;
|
||||
else {
|
||||
debug("%s: Codec id [%d] not defined\n", __func__,
|
||||
pcodec_info->codec_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = max98095_device_init(&g_max98095_info);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98095 codec chip init failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98095 codec set sys clock failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_hw_params(&g_max98095_info, sampling_rate,
|
||||
bits_per_sample);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = max98095_set_fmt(&g_max98095_info,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
|
||||
const void *blob)
|
||||
{
|
||||
int error = 0;
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
enum fdt_compat_id compat;
|
||||
int node;
|
||||
int parent;
|
||||
|
||||
/* Get the node from FDT for codec */
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC);
|
||||
if (node <= 0) {
|
||||
debug("EXYNOS_SOUND: No node for codec in device tree\n");
|
||||
debug("node = %d\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
parent = fdt_parent_offset(blob, node);
|
||||
if (parent < 0) {
|
||||
debug("%s: Cannot find node parent\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
compat = fdtdec_lookup(blob, parent);
|
||||
switch (compat) {
|
||||
case COMPAT_SAMSUNG_S3C2440_I2C:
|
||||
pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
|
||||
error |= pcodec_info->i2c_bus;
|
||||
debug("i2c bus = %d\n", pcodec_info->i2c_bus);
|
||||
pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
|
||||
"reg", 0);
|
||||
error |= pcodec_info->i2c_dev_addr;
|
||||
debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unknown compat id %d\n", __func__, compat);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
pcodec_info->i2c_bus = AUDIO_I2C_BUS;
|
||||
pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
|
||||
debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
|
||||
#endif
|
||||
pcodec_info->codec_type = CODEC_MAX_98095;
|
||||
if (error == -1) {
|
||||
debug("fail to get max98095 codec node properties\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* max98095 Device Initialisation */
|
||||
int max98095_init(const void *blob, int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample)
|
||||
{
|
||||
int ret;
|
||||
int old_bus = i2c_get_bus_num();
|
||||
struct sound_codec_info *pcodec_info = &g_codec_info;
|
||||
|
||||
if (get_max98095_codec_values(pcodec_info, blob) < 0) {
|
||||
debug("FDT Codec values failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i2c_set_bus_num(pcodec_info->i2c_bus);
|
||||
ret = max98095_do_init(pcodec_info, sampling_rate, mclk_freq,
|
||||
bits_per_sample);
|
||||
i2c_set_bus_num(old_bus);
|
||||
|
||||
return ret;
|
||||
}
|
311
drivers/sound/max98095.h
Normal file
311
drivers/sound/max98095.h
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* max98095.h -- MAX98095 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _MAX98095_H
|
||||
#define _MAX98095_H
|
||||
|
||||
/*
|
||||
* MAX98095 Registers Definition
|
||||
*/
|
||||
|
||||
#define M98095_000_HOST_DATA 0x00
|
||||
#define M98095_001_HOST_INT_STS 0x01
|
||||
#define M98095_002_HOST_RSP_STS 0x02
|
||||
#define M98095_003_HOST_CMD_STS 0x03
|
||||
#define M98095_004_CODEC_STS 0x04
|
||||
#define M98095_005_DAI1_ALC_STS 0x05
|
||||
#define M98095_006_DAI2_ALC_STS 0x06
|
||||
#define M98095_007_JACK_AUTO_STS 0x07
|
||||
#define M98095_008_JACK_MANUAL_STS 0x08
|
||||
#define M98095_009_JACK_VBAT_STS 0x09
|
||||
#define M98095_00A_ACC_ADC_STS 0x0A
|
||||
#define M98095_00B_MIC_NG_AGC_STS 0x0B
|
||||
#define M98095_00C_SPK_L_VOLT_STS 0x0C
|
||||
#define M98095_00D_SPK_R_VOLT_STS 0x0D
|
||||
#define M98095_00E_TEMP_SENSOR_STS 0x0E
|
||||
#define M98095_00F_HOST_CFG 0x0F
|
||||
#define M98095_010_HOST_INT_CFG 0x10
|
||||
#define M98095_011_HOST_INT_EN 0x11
|
||||
#define M98095_012_CODEC_INT_EN 0x12
|
||||
#define M98095_013_JACK_INT_EN 0x13
|
||||
#define M98095_014_JACK_INT_EN 0x14
|
||||
#define M98095_015_DEC 0x15
|
||||
#define M98095_016_RESERVED 0x16
|
||||
#define M98095_017_RESERVED 0x17
|
||||
#define M98095_018_KEYCODE3 0x18
|
||||
#define M98095_019_KEYCODE2 0x19
|
||||
#define M98095_01A_KEYCODE1 0x1A
|
||||
#define M98095_01B_KEYCODE0 0x1B
|
||||
#define M98095_01C_OEMCODE1 0x1C
|
||||
#define M98095_01D_OEMCODE0 0x1D
|
||||
#define M98095_01E_XCFG1 0x1E
|
||||
#define M98095_01F_XCFG2 0x1F
|
||||
#define M98095_020_XCFG3 0x20
|
||||
#define M98095_021_XCFG4 0x21
|
||||
#define M98095_022_XCFG5 0x22
|
||||
#define M98095_023_XCFG6 0x23
|
||||
#define M98095_024_XGPIO 0x24
|
||||
#define M98095_025_XCLKCFG 0x25
|
||||
#define M98095_026_SYS_CLK 0x26
|
||||
#define M98095_027_DAI1_CLKMODE 0x27
|
||||
#define M98095_028_DAI1_CLKCFG_HI 0x28
|
||||
#define M98095_029_DAI1_CLKCFG_LO 0x29
|
||||
#define M98095_02A_DAI1_FORMAT 0x2A
|
||||
#define M98095_02B_DAI1_CLOCK 0x2B
|
||||
#define M98095_02C_DAI1_IOCFG 0x2C
|
||||
#define M98095_02D_DAI1_TDM 0x2D
|
||||
#define M98095_02E_DAI1_FILTERS 0x2E
|
||||
#define M98095_02F_DAI1_LVL1 0x2F
|
||||
#define M98095_030_DAI1_LVL2 0x30
|
||||
#define M98095_031_DAI2_CLKMODE 0x31
|
||||
#define M98095_032_DAI2_CLKCFG_HI 0x32
|
||||
#define M98095_033_DAI2_CLKCFG_LO 0x33
|
||||
#define M98095_034_DAI2_FORMAT 0x34
|
||||
#define M98095_035_DAI2_CLOCK 0x35
|
||||
#define M98095_036_DAI2_IOCFG 0x36
|
||||
#define M98095_037_DAI2_TDM 0x37
|
||||
#define M98095_038_DAI2_FILTERS 0x38
|
||||
#define M98095_039_DAI2_LVL1 0x39
|
||||
#define M98095_03A_DAI2_LVL2 0x3A
|
||||
#define M98095_03B_DAI3_CLKMODE 0x3B
|
||||
#define M98095_03C_DAI3_CLKCFG_HI 0x3C
|
||||
#define M98095_03D_DAI3_CLKCFG_LO 0x3D
|
||||
#define M98095_03E_DAI3_FORMAT 0x3E
|
||||
#define M98095_03F_DAI3_CLOCK 0x3F
|
||||
#define M98095_040_DAI3_IOCFG 0x40
|
||||
#define M98095_041_DAI3_TDM 0x41
|
||||
#define M98095_042_DAI3_FILTERS 0x42
|
||||
#define M98095_043_DAI3_LVL1 0x43
|
||||
#define M98095_044_DAI3_LVL2 0x44
|
||||
#define M98095_045_CFG_DSP 0x45
|
||||
#define M98095_046_DAC_CTRL1 0x46
|
||||
#define M98095_047_DAC_CTRL2 0x47
|
||||
#define M98095_048_MIX_DAC_LR 0x48
|
||||
#define M98095_049_MIX_DAC_M 0x49
|
||||
#define M98095_04A_MIX_ADC_LEFT 0x4A
|
||||
#define M98095_04B_MIX_ADC_RIGHT 0x4B
|
||||
#define M98095_04C_MIX_HP_LEFT 0x4C
|
||||
#define M98095_04D_MIX_HP_RIGHT 0x4D
|
||||
#define M98095_04E_CFG_HP 0x4E
|
||||
#define M98095_04F_MIX_RCV 0x4F
|
||||
#define M98095_050_MIX_SPK_LEFT 0x50
|
||||
#define M98095_051_MIX_SPK_RIGHT 0x51
|
||||
#define M98095_052_MIX_SPK_CFG 0x52
|
||||
#define M98095_053_MIX_LINEOUT1 0x53
|
||||
#define M98095_054_MIX_LINEOUT2 0x54
|
||||
#define M98095_055_MIX_LINEOUT_CFG 0x55
|
||||
#define M98095_056_LVL_SIDETONE_DAI12 0x56
|
||||
#define M98095_057_LVL_SIDETONE_DAI3 0x57
|
||||
#define M98095_058_LVL_DAI1_PLAY 0x58
|
||||
#define M98095_059_LVL_DAI1_EQ 0x59
|
||||
#define M98095_05A_LVL_DAI2_PLAY 0x5A
|
||||
#define M98095_05B_LVL_DAI2_EQ 0x5B
|
||||
#define M98095_05C_LVL_DAI3_PLAY 0x5C
|
||||
#define M98095_05D_LVL_ADC_L 0x5D
|
||||
#define M98095_05E_LVL_ADC_R 0x5E
|
||||
#define M98095_05F_LVL_MIC1 0x5F
|
||||
#define M98095_060_LVL_MIC2 0x60
|
||||
#define M98095_061_LVL_LINEIN 0x61
|
||||
#define M98095_062_LVL_LINEOUT1 0x62
|
||||
#define M98095_063_LVL_LINEOUT2 0x63
|
||||
#define M98095_064_LVL_HP_L 0x64
|
||||
#define M98095_065_LVL_HP_R 0x65
|
||||
#define M98095_066_LVL_RCV 0x66
|
||||
#define M98095_067_LVL_SPK_L 0x67
|
||||
#define M98095_068_LVL_SPK_R 0x68
|
||||
#define M98095_069_MICAGC_CFG 0x69
|
||||
#define M98095_06A_MICAGC_THRESH 0x6A
|
||||
#define M98095_06B_SPK_NOISEGATE 0x6B
|
||||
#define M98095_06C_DAI1_ALC1_TIME 0x6C
|
||||
#define M98095_06D_DAI1_ALC1_COMP 0x6D
|
||||
#define M98095_06E_DAI1_ALC1_EXPN 0x6E
|
||||
#define M98095_06F_DAI1_ALC1_GAIN 0x6F
|
||||
#define M98095_070_DAI1_ALC2_TIME 0x70
|
||||
#define M98095_071_DAI1_ALC2_COMP 0x71
|
||||
#define M98095_072_DAI1_ALC2_EXPN 0x72
|
||||
#define M98095_073_DAI1_ALC2_GAIN 0x73
|
||||
#define M98095_074_DAI1_ALC3_TIME 0x74
|
||||
#define M98095_075_DAI1_ALC3_COMP 0x75
|
||||
#define M98095_076_DAI1_ALC3_EXPN 0x76
|
||||
#define M98095_077_DAI1_ALC3_GAIN 0x77
|
||||
#define M98095_078_DAI2_ALC1_TIME 0x78
|
||||
#define M98095_079_DAI2_ALC1_COMP 0x79
|
||||
#define M98095_07A_DAI2_ALC1_EXPN 0x7A
|
||||
#define M98095_07B_DAI2_ALC1_GAIN 0x7B
|
||||
#define M98095_07C_DAI2_ALC2_TIME 0x7C
|
||||
#define M98095_07D_DAI2_ALC2_COMP 0x7D
|
||||
#define M98095_07E_DAI2_ALC2_EXPN 0x7E
|
||||
#define M98095_07F_DAI2_ALC2_GAIN 0x7F
|
||||
#define M98095_080_DAI2_ALC3_TIME 0x80
|
||||
#define M98095_081_DAI2_ALC3_COMP 0x81
|
||||
#define M98095_082_DAI2_ALC3_EXPN 0x82
|
||||
#define M98095_083_DAI2_ALC3_GAIN 0x83
|
||||
#define M98095_084_HP_NOISE_GATE 0x84
|
||||
#define M98095_085_AUX_ADC 0x85
|
||||
#define M98095_086_CFG_LINE 0x86
|
||||
#define M98095_087_CFG_MIC 0x87
|
||||
#define M98095_088_CFG_LEVEL 0x88
|
||||
#define M98095_089_JACK_DET_AUTO 0x89
|
||||
#define M98095_08A_JACK_DET_MANUAL 0x8A
|
||||
#define M98095_08B_JACK_KEYSCAN_DBC 0x8B
|
||||
#define M98095_08C_JACK_KEYSCAN_DLY 0x8C
|
||||
#define M98095_08D_JACK_KEY_THRESH 0x8D
|
||||
#define M98095_08E_JACK_DC_SLEW 0x8E
|
||||
#define M98095_08F_JACK_TEST_CFG 0x8F
|
||||
#define M98095_090_PWR_EN_IN 0x90
|
||||
#define M98095_091_PWR_EN_OUT 0x91
|
||||
#define M98095_092_PWR_EN_OUT 0x92
|
||||
#define M98095_093_BIAS_CTRL 0x93
|
||||
#define M98095_094_PWR_DAC_21 0x94
|
||||
#define M98095_095_PWR_DAC_03 0x95
|
||||
#define M98095_096_PWR_DAC_CK 0x96
|
||||
#define M98095_097_PWR_SYS 0x97
|
||||
|
||||
#define M98095_0FF_REV_ID 0xFF
|
||||
|
||||
#define M98095_REG_CNT (0xFF+1)
|
||||
#define M98095_REG_MAX_CACHED 0X97
|
||||
|
||||
/* MAX98095 Registers Bit Fields */
|
||||
|
||||
/* M98095_00F_HOST_CFG */
|
||||
#define M98095_SEG (1<<0)
|
||||
#define M98095_XTEN (1<<1)
|
||||
#define M98095_MDLLEN (1<<2)
|
||||
|
||||
/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
|
||||
#define M98095_CLKMODE_MASK 0xFF
|
||||
|
||||
/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
|
||||
#define M98095_DAI_MAS (1<<7)
|
||||
#define M98095_DAI_WCI (1<<6)
|
||||
#define M98095_DAI_BCI (1<<5)
|
||||
#define M98095_DAI_DLY (1<<4)
|
||||
#define M98095_DAI_TDM (1<<2)
|
||||
#define M98095_DAI_FSW (1<<1)
|
||||
#define M98095_DAI_WS (1<<0)
|
||||
|
||||
/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
|
||||
#define M98095_DAI_BSEL64 (1<<0)
|
||||
#define M98095_DAI_DOSR_DIV2 (0<<5)
|
||||
#define M98095_DAI_DOSR_DIV4 (1<<5)
|
||||
|
||||
/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
|
||||
#define M98095_S1NORMAL (1<<6)
|
||||
#define M98095_S2NORMAL (2<<6)
|
||||
#define M98095_S3NORMAL (3<<6)
|
||||
#define M98095_SDATA (3<<0)
|
||||
|
||||
/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
|
||||
#define M98095_DAI_DHF (1<<3)
|
||||
|
||||
/* M98095_045_DSP_CFG */
|
||||
#define M98095_DSPNORMAL (5<<4)
|
||||
|
||||
/* M98095_048_MIX_DAC_LR */
|
||||
#define M98095_DAI1L_TO_DACR (1<<7)
|
||||
#define M98095_DAI1R_TO_DACR (1<<6)
|
||||
#define M98095_DAI2M_TO_DACR (1<<5)
|
||||
#define M98095_DAI1L_TO_DACL (1<<3)
|
||||
#define M98095_DAI1R_TO_DACL (1<<2)
|
||||
#define M98095_DAI2M_TO_DACL (1<<1)
|
||||
#define M98095_DAI3M_TO_DACL (1<<0)
|
||||
|
||||
/* M98095_049_MIX_DAC_M */
|
||||
#define M98095_DAI1L_TO_DACM (1<<3)
|
||||
#define M98095_DAI1R_TO_DACM (1<<2)
|
||||
#define M98095_DAI2M_TO_DACM (1<<1)
|
||||
#define M98095_DAI3M_TO_DACM (1<<0)
|
||||
|
||||
/* M98095_04E_MIX_HP_CFG */
|
||||
#define M98095_HPNORMAL (3<<4)
|
||||
|
||||
/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
|
||||
#define M98095_MICPRE_MASK (3<<5)
|
||||
#define M98095_MICPRE_SHIFT 5
|
||||
|
||||
/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
|
||||
#define M98095_HP_MUTE (1<<7)
|
||||
|
||||
/* M98095_066_LVL_RCV */
|
||||
#define M98095_REC_MUTE (1<<7)
|
||||
|
||||
/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
|
||||
#define M98095_SP_MUTE (1<<7)
|
||||
|
||||
/* M98095_087_CFG_MIC */
|
||||
#define M98095_MICSEL_MASK (3<<0)
|
||||
#define M98095_DIGMIC_L (1<<2)
|
||||
#define M98095_DIGMIC_R (1<<3)
|
||||
#define M98095_DIGMIC2L (1<<4)
|
||||
#define M98095_DIGMIC2R (1<<5)
|
||||
|
||||
/* M98095_088_CFG_LEVEL */
|
||||
#define M98095_VSEN (1<<6)
|
||||
#define M98095_ZDEN (1<<5)
|
||||
#define M98095_BQ2EN (1<<3)
|
||||
#define M98095_BQ1EN (1<<2)
|
||||
#define M98095_EQ2EN (1<<1)
|
||||
#define M98095_EQ1EN (1<<0)
|
||||
|
||||
/* M98095_090_PWR_EN_IN */
|
||||
#define M98095_INEN (1<<7)
|
||||
#define M98095_MB2EN (1<<3)
|
||||
#define M98095_MB1EN (1<<2)
|
||||
#define M98095_MBEN (3<<2)
|
||||
#define M98095_ADREN (1<<1)
|
||||
#define M98095_ADLEN (1<<0)
|
||||
|
||||
/* M98095_091_PWR_EN_OUT */
|
||||
#define M98095_HPLEN (1<<7)
|
||||
#define M98095_HPREN (1<<6)
|
||||
#define M98095_SPLEN (1<<5)
|
||||
#define M98095_SPREN (1<<4)
|
||||
#define M98095_RECEN (1<<3)
|
||||
#define M98095_DALEN (1<<1)
|
||||
#define M98095_DAREN (1<<0)
|
||||
|
||||
/* M98095_092_PWR_EN_OUT */
|
||||
#define M98095_SPK_FIXEDSPECTRUM (0<<4)
|
||||
#define M98095_SPK_SPREADSPECTRUM (1<<4)
|
||||
|
||||
/* M98095_097_PWR_SYS */
|
||||
#define M98095_SHDNRUN (1<<7)
|
||||
#define M98095_PERFMODE (1<<3)
|
||||
#define M98095_HPPLYBACK (1<<2)
|
||||
#define M98095_PWRSV8K (1<<1)
|
||||
#define M98095_PWRSV (1<<0)
|
||||
|
||||
#define M98095_COEFS_PER_BAND 5
|
||||
|
||||
/* Equalizer filter coefficients */
|
||||
#define M98095_110_DAI1_EQ_BASE 0x10
|
||||
#define M98095_142_DAI2_EQ_BASE 0x42
|
||||
|
||||
/* Biquad filter coefficients */
|
||||
#define M98095_174_DAI1_BQ_BASE 0x74
|
||||
#define M98095_17E_DAI2_BQ_BASE 0x7E
|
||||
|
||||
/* function prototype */
|
||||
|
||||
/*
|
||||
* intialise max98095 sound codec device for the given configuration
|
||||
*
|
||||
* @param blob FDT node for codec values
|
||||
* @param sampling_rate Sampling rate (Hz)
|
||||
* @param mclk_freq MCLK Frequency (Hz)
|
||||
* @param bits_per_sample bits per Sample (must be 16 or 24)
|
||||
*
|
||||
* @returns -1 for error and 0 Success.
|
||||
*/
|
||||
int max98095_init(const void *blob, int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample);
|
||||
|
||||
#endif
|
@ -31,6 +31,7 @@
|
||||
#include <sound.h>
|
||||
#include <asm/arch/sound.h>
|
||||
#include "wm8994.h"
|
||||
#include "max98095.h"
|
||||
|
||||
/* defines */
|
||||
#define SOUND_400_HZ 400
|
||||
@ -149,11 +150,15 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
|
||||
pi2s_tx->samplingrate,
|
||||
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
|
||||
pi2s_tx->bitspersample, pi2s_tx->channels);
|
||||
} else if (!strcmp(codectype, "max98095")) {
|
||||
ret = max98095_init(blob, pi2s_tx->samplingrate,
|
||||
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
|
||||
pi2s_tx->bitspersample);
|
||||
} else {
|
||||
debug("%s: Unknown code type %s\n", __func__,
|
||||
codectype);
|
||||
debug("%s: Unknown codec type %s\n", __func__, codectype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
debug("%s: Codec init failed\n", __func__);
|
||||
return -1;
|
||||
|
@ -118,6 +118,11 @@
|
||||
#define CONFIG_BOOTDELAY 3
|
||||
#define CONFIG_ZERO_BOOTDELAY_CHECK
|
||||
|
||||
/* Thermal Management Unit */
|
||||
#define CONFIG_EXYNOS_TMU
|
||||
#define CONFIG_CMD_DTT
|
||||
#define CONFIG_TMU_CMD_DTT
|
||||
|
||||
/* USB */
|
||||
#define CONFIG_CMD_USB
|
||||
#define CONFIG_USB_EHCI
|
||||
@ -297,6 +302,7 @@
|
||||
#ifdef CONFIG_CMD_SOUND
|
||||
#define CONFIG_SOUND
|
||||
#define CONFIG_I2S
|
||||
#define CONFIG_SOUND_MAX98095
|
||||
#define CONFIG_SOUND_WM8994
|
||||
#endif
|
||||
|
||||
|
33
include/configs/snow.h
Normal file
33
include/configs/snow.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Samsung Electronics
|
||||
*
|
||||
* Configuration settings for the SAMSUNG EXYNOS5 Snow board.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_SNOW_H
|
||||
#define __CONFIG_SNOW_H
|
||||
|
||||
#include <configs/exynos5250-dt.h>
|
||||
|
||||
#undef CONFIG_DEFAULT_DEVICE_TREE
|
||||
#define CONFIG_DEFAULT_DEVICE_TREE exynos5250-snow
|
||||
|
||||
#endif /* __CONFIG_SNOW_H */
|
@ -83,7 +83,9 @@ enum fdt_compat_id {
|
||||
COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */
|
||||
COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
|
||||
COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
|
||||
COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
|
||||
COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */
|
||||
COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */
|
||||
|
||||
COMPAT_COUNT,
|
||||
};
|
||||
|
@ -155,4 +155,36 @@ enum {
|
||||
EN_LDO = (0x3 << 6),
|
||||
};
|
||||
|
||||
/* Buck1 1 volt value */
|
||||
#define MAX77686_BUCK1OUT_1V 0x5
|
||||
#define MAX77686_BUCK1CTRL_EN (3 << 0)
|
||||
/* Buck2 1.3 volt value */
|
||||
#define MAX77686_BUCK2DVS1_1_3V 0x38
|
||||
#define MAX77686_BUCK2CTRL_ON (1 << 4)
|
||||
/* Buck3 1.0125 volt value */
|
||||
#define MAX77686_BUCK3DVS1_1_0125V 0x21
|
||||
#define MAX77686_BUCK3CTRL_ON (1 << 4)
|
||||
/* Buck4 1.2 volt value */
|
||||
#define MAX77686_BUCK4DVS1_1_2V 0x30
|
||||
#define MAX77686_BUCK4CTRL_ON (1 << 4)
|
||||
/* LDO2 1.5 volt value */
|
||||
#define MAX77686_LD02CTRL1_1_5V 0x1c
|
||||
/* LDO3 1.8 volt value */
|
||||
#define MAX77686_LD03CTRL1_1_8V 0x14
|
||||
/* LDO5 1.8 volt value */
|
||||
#define MAX77686_LD05CTRL1_1_8V 0x14
|
||||
/* LDO10 1.8 volt value */
|
||||
#define MAX77686_LD10CTRL1_1_8V 0x14
|
||||
/*
|
||||
* MAX77686_REG_PMIC_32KHZ set to 32KH CP
|
||||
* output is activated
|
||||
*/
|
||||
#define MAX77686_32KHCP_EN (1 << 1)
|
||||
/*
|
||||
* MAX77686_REG_PMIC_BBAT set to
|
||||
* Back up batery charger on and
|
||||
* limit voltage setting to 3.5v
|
||||
*/
|
||||
#define MAX77686_BBCHOSTEN (1 << 0)
|
||||
#define MAX77686_BBCVS_3_5V (3 << 3)
|
||||
#endif /* __MAX77686_PMIC_H_ */
|
||||
|
@ -28,6 +28,7 @@
|
||||
enum en_sound_codec {
|
||||
CODEC_WM_8994,
|
||||
CODEC_WM_8995,
|
||||
CODEC_MAX_98095,
|
||||
CODEC_MAX
|
||||
};
|
||||
|
||||
|
46
include/tmu.h
Normal file
46
include/tmu.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
* Akshay Saraswat <akshay.s@samsung.com>
|
||||
*
|
||||
* Thermal Management Unit
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _TMU_H
|
||||
#define _TMU_H
|
||||
|
||||
enum tmu_status_t {
|
||||
TMU_STATUS_INIT = -1,
|
||||
TMU_STATUS_NORMAL = 0,
|
||||
TMU_STATUS_WARNING,
|
||||
TMU_STATUS_TRIPPED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Monitors status of the TMU device and exynos temperature
|
||||
*
|
||||
* @param temp pointer to the current temperature value
|
||||
* @return enum tmu_status_t value, code indicating event to execute
|
||||
* and -1 on error
|
||||
*/
|
||||
enum tmu_status_t tmu_monitor(int *temp);
|
||||
|
||||
/*
|
||||
* Initialize TMU device
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
int tmu_init(const void *blob);
|
||||
#endif /* _THERMAL_H_ */
|
@ -58,7 +58,9 @@ static const char * const compat_names[COMPAT_COUNT] = {
|
||||
COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
|
||||
COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
|
||||
COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
|
||||
COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
|
||||
COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
|
||||
COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
|
||||
};
|
||||
|
||||
const char *fdtdec_get_compatible(enum fdt_compat_id id)
|
||||
|
Loading…
Reference in New Issue
Block a user