From 51ff1eda6f788fc76666d275a87a7c7aff32baa8 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 12 Feb 2013 20:40:01 +0000 Subject: EXYNOS5: Add function to setup set ps hold This patch adds a function to set ps_hold data driving value high. This enables the machine to stay powered on even after the initial power-on condition goes away(e.g. power button). Acked-by: Simon Glass Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 16 ++++++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index d4bce6d..400c8bc 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -95,3 +95,19 @@ 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(); +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index d2fdb59..f2f73fa 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -864,4 +864,13 @@ void set_dp_phy_ctrl(unsigned int enable); #define EXYNOS_DP_PHY_ENABLE (1 << 0) +#define EXYNOS_PS_HOLD_CONTROL_DATA_HIGH (1 << 8) + +/* + * 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); #endif -- cgit v1.1 From b278c4095b59c40ff512c5433b735b000e547554 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 12 Feb 2013 20:40:02 +0000 Subject: SMDK5250: Add PMIC voltage settings This patch adds required pmic voltage settings for SMDK5250. Acked-by: Simon Glass Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 113 +++++++++++++++++++++++++++++++++++++- include/power/max77686_pmic.h | 32 +++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 7a5f132..ffc5ee5 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -80,12 +82,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 diff --git a/include/power/max77686_pmic.h b/include/power/max77686_pmic.h index d949ace..fdc7ca9 100644 --- a/include/power/max77686_pmic.h +++ b/include/power/max77686_pmic.h @@ -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_ */ -- cgit v1.1 From a006076b15c32e2f9c2c133697b5c662f7d1294e Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:11 +0000 Subject: EXYNOS5: Add function to enable XXTI clock source This patch adds funtion to enable XXTI clock source required by MAX98095 codec. Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 17 +++++++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index 400c8bc..db7249e 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -111,3 +111,20 @@ 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(); +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index f2f73fa..5f26337 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -873,4 +873,15 @@ void set_dp_phy_ctrl(unsigned int enable); * (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 -- cgit v1.1 From 5febe8db91a9feca467ce8e0189a69b49cba02e7 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:12 +0000 Subject: Sound: MAX98095: Add the driver for codec This patch adds the driver for codec MAX98095 required by Snow Board Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- drivers/sound/Makefile | 1 + drivers/sound/max98095.c | 550 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/sound/max98095.h | 311 +++++++++++++++++++++++++++ 3 files changed, 862 insertions(+) create mode 100644 drivers/sound/max98095.c create mode 100644 drivers/sound/max98095.h diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 8fdffb1..1987ca1 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -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) diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c new file mode 100644 index 0000000..d69db58 --- /dev/null +++ b/drivers/sound/max98095.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h new file mode 100644 index 0000000..ae5eb14 --- /dev/null +++ b/drivers/sound/max98095.h @@ -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 -- cgit v1.1 From 14d2dfc33a087cf98ae37e453edd294c7835caae Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:13 +0000 Subject: Sound: Support for MAX98095 codec in driver This patchs adds support for MAX98095 codec in sound driver. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- drivers/sound/sound.c | 9 +++++++-- include/sound.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index fa8432d..a4bf4ad 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -31,6 +31,7 @@ #include #include #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; diff --git a/include/sound.h b/include/sound.h index d73839d..94922f6 100644 --- a/include/sound.h +++ b/include/sound.h @@ -28,6 +28,7 @@ enum en_sound_codec { CODEC_WM_8994, CODEC_WM_8995, + CODEC_MAX_98095, CODEC_MAX }; -- cgit v1.1 From ce07380534a9fc3cba2b3c1f97932d126ef9979a Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:14 +0000 Subject: EXYNOS5: GPIO to enable MAX98095 This patch sets high a GPIO to enable the codec MAX98095 Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index ffc5ee5..6f6f2c2 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -56,6 +56,18 @@ 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); @@ -65,6 +77,9 @@ int board_init(void) #ifdef CONFIG_USB_EHCI_EXYNOS board_usb_vbus_init(); #endif +#ifdef CONFIG_SOUND_MAX98095 + board_enable_audio_codec(); +#endif return 0; } -- cgit v1.1 From 7772bb787e50eb93544755dd8d21180d28a1f8ee Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:15 +0000 Subject: EXYNOS5: FDT: Add compatible strings for MAX98095 Add required compatible information for MAX98095 codec Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/fdtdec.h b/include/fdtdec.h index 77f244f..b885a95 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -81,6 +81,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */ + COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */ COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 3ae348d..9a527ff 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -56,6 +56,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), + COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- cgit v1.1 From cfa6df19091ec831a4767fe36907abb8a8e99f84 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:16 +0000 Subject: config: Snow: Enable MAX98095 codec This patch enables MAX98095 codec required for Snow Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index cabd2f2..89fcda5 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -296,6 +296,7 @@ #ifdef CONFIG_CMD_SOUND #define CONFIG_SOUND #define CONFIG_I2S +#define CONFIG_SOUND_MAX98095 #define CONFIG_SOUND_WM8994 #endif -- cgit v1.1 From c42ffff02a1edd24fc50e5efb33ead1bfa843a26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Feb 2013 20:32:59 +0000 Subject: EXYNOS: Correct ordering of SPL machine_params The mem_manuf is not in the correct order according to the string table. This causes cros_bundle_firmware to get the BL2 settings in the wrong order. This patch fixes the same. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/include/asm/arch-exynos/spl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-exynos/spl.h b/arch/arm/include/asm/arch-exynos/spl.h index 306b41d..46b25a6 100644 --- a/arch/arm/include/asm/arch-exynos/spl.h +++ b/arch/arm/include/asm/arch-exynos/spl.h @@ -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 -- cgit v1.1 From 07f17507c4309d3ccc1fbfd912d078a9ca609aba Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 18 Feb 2013 02:51:49 +0000 Subject: SMDK5250: FDT: Retrieve board model via DT Print out the board model by parsing the device tree file. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 6f6f2c2..0097b3f 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -336,8 +336,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 -- cgit v1.1 From 39d182d3de5dcfaeb7d6997be4ab764081ff529e Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:00 +0000 Subject: Exynos5: TMU: Add driver for Thermal Management Unit Adding Exynos Thermal Management Unit driver to monitor SOC temperature and take actions corresponding to states of TMU. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/include/asm/arch-exynos/tmu.h | 58 +++++++ drivers/power/Makefile | 1 + drivers/power/exynos-tmu.c | 304 +++++++++++++++++++++++++++++++++ include/tmu.h | 46 +++++ 4 files changed, 409 insertions(+) create mode 100644 arch/arm/include/asm/arch-exynos/tmu.h create mode 100644 drivers/power/exynos-tmu.c create mode 100644 include/tmu.h diff --git a/arch/arm/include/asm/arch-exynos/tmu.h b/arch/arm/include/asm/arch-exynos/tmu.h new file mode 100644 index 0000000..7e0158e --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/tmu.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * 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 */ diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 8c71901..1dac16a 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -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 diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c new file mode 100644 index 0000000..d8313b1 --- /dev/null +++ b/drivers/power/exynos-tmu.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * 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 +#include +#include +#include +#include + +#define TRIMINFO_RELOAD 1 +#define CORE_EN 1 + +#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; +}; + +/* 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.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; + 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; + cooling_temp = 0; + + rising_value = ((warning_code << 8) | (trip_code << 16)); + + /* 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 |= CORE_EN; + + writel(con, ®->tmu_control); + + /* LEV0 LEV1 LEV2 interrupt enable */ + writel(INTEN_RISE0 | 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; +} diff --git a/include/tmu.h b/include/tmu.h new file mode 100644 index 0000000..da07a22 --- /dev/null +++ b/include/tmu.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * 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_ */ -- cgit v1.1 From 618766c09855f7167f510eafa89172ae44cae543 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:01 +0000 Subject: Exynos5: FDT: Add TMU device node values Fdt entry for Exynos TMU driver specific pre-defined values used for calibration of current temperature and defining threshold values. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/dts/exynos5250.dtsi | 5 ++++ board/samsung/dts/exynos5250-smdk5250.dts | 12 +++++++++ doc/device-tree-bindings/exynos/tmu.txt | 41 +++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 5 files changed, 60 insertions(+) create mode 100644 doc/device-tree-bindings/exynos/tmu.txt diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index ed8c8dd..61d35a8 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -151,4 +151,9 @@ }; }; + tmu@10060000 { + compatible = "samsung,exynos-tmu"; + reg = <0x10060000 0x10000>; + }; + }; diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index cbfab6f..00dac40 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -66,4 +66,16 @@ compatible = "maxim,max77686_pmic"; }; }; + + tmu@10060000 { + samsung,min-temp = <25>; + samsung,max-temp = <125>; + samsung,start-warning = <95>; + samsung,start-tripping = <105>; + samsung,efuse-min-value = <40>; + samsung,efuse-value = <55>; + samsung,efuse-max-value = <100>; + samsung,slope = <274761730>; + samsung,dc-value = <25>; + }; }; diff --git a/doc/device-tree-bindings/exynos/tmu.txt b/doc/device-tree-bindings/exynos/tmu.txt new file mode 100644 index 0000000..bb734dc --- /dev/null +++ b/doc/device-tree-bindings/exynos/tmu.txt @@ -0,0 +1,41 @@ +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 system will trip and shutdown (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,efuse-min-value = <40>; + samsung,efuse-value = <55>; + samsung,efuse-max-value = <100>; + samsung,slope = <274761730>; + samsung,dc-value = <25>; +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index b885a95..6552942 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -80,6 +80,7 @@ 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 */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 9a527ff..88f6b68 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -55,6 +55,7 @@ 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"), }; -- cgit v1.1 From 7e30ad8bf3c6f7768158ad994b9180c6906fa5da Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:02 +0000 Subject: Exynos5: TMU: Add TMU init and status check This adds call to tmu_init() and TMU boot time analysis for the SoC temperature threshold breach. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 0097b3f..217c6df 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -37,9 +37,39 @@ #include #include #include +#include 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) { @@ -71,6 +101,15 @@ static void board_enable_audio_codec(void) 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 -- cgit v1.1 From f7f85f7dc32143593d8e2ed85f3ab844c9c9c0ff Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:03 +0000 Subject: Exynos5: Config: Enable support for Exynos TMU driver Enables TMU driver support for exynos5250 Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index 89fcda5..fe9a3c6 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -117,6 +117,9 @@ #define CONFIG_BOOTDELAY 3 #define CONFIG_ZERO_BOOTDELAY_CHECK +/* Thermal Management Unit */ +#define CONFIG_EXYNOS_TMU + /* USB */ #define CONFIG_CMD_USB #define CONFIG_USB_EHCI -- cgit v1.1 From bc5478b2757c9ee0068056206ea52f93ada544c8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:04 +0000 Subject: TMU: Add TMU support in dtt command Add generic TMU support alongwith i2c sensors in dtt command to enable temperature reading in cases where TMU is present along-with/instead-of i2c sensors. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- common/cmd_dtt.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/common/cmd_dtt.c b/common/cmd_dtt.c index cd94423..edbd4a8 100644 --- a/common/cmd_dtt.c +++ b/common/cmd_dtt.c @@ -27,7 +27,9 @@ #include #include +#include +#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() */ /***************************************************/ -- cgit v1.1 From 8afcfc212415b8bacdf08b752aef7976e7da52a8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:05 +0000 Subject: Exynos5: Config: Enable dtt command for TMU This enables the dtt command to read the current SOC temperature with the help of TMU Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index fe9a3c6..f334d45 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -119,6 +119,8 @@ /* Thermal Management Unit */ #define CONFIG_EXYNOS_TMU +#define CONFIG_CMD_DTT +#define CONFIG_TMU_CMD_DTT /* USB */ #define CONFIG_CMD_USB -- cgit v1.1 From 3a0b1dae5b9b853559b87a2332a27d1ed6a91fb8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:06 +0000 Subject: Exynos5: TMU: Add hardware tripping This adds hardware tripping at 110 degrees celsius which must enable forced system shutdown in case TMU fails to power off. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 12 ++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 4 ++++ drivers/power/exynos-tmu.c | 25 ++++++++++++++++++++----- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index db7249e..6375a81 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -128,3 +128,15 @@ 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); + } +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index 5f26337..3549667 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -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) @@ -865,6 +868,7 @@ 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 diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c index d8313b1..d4b3e65 100644 --- a/drivers/power/exynos-tmu.c +++ b/drivers/power/exynos-tmu.c @@ -22,9 +22,11 @@ #include #include #include +#include #define TRIMINFO_RELOAD 1 #define CORE_EN 1 +#define THERM_TRIP_EN (1 << 12) #define INTEN_RISE0 1 #define INTEN_RISE1 (1 << 4) @@ -55,6 +57,8 @@ struct temperature_params { 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 */ @@ -196,6 +200,9 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob) 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; @@ -230,7 +237,7 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob) static void tmu_setup_parameters(struct tmu_info *info) { unsigned int te_code, con; - unsigned int warning_code, trip_code; + unsigned int warning_code, trip_code, hwtrip_code; unsigned int cooling_temp; unsigned int rising_value; struct tmu_data *data = &info->data; @@ -254,9 +261,14 @@ static void tmu_setup_parameters(struct tmu_info *info) + 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)); + rising_value = ((warning_code << 8) | + (trip_code << 16) | + (hwtrip_code << 24)); /* Set interrupt level */ writel(rising_value, ®->threshold_temp_rise); @@ -276,12 +288,15 @@ static void tmu_setup_parameters(struct tmu_info *info) /* TMU core enable */ con = readl(®->tmu_control); - con |= CORE_EN; + con |= THERM_TRIP_EN | CORE_EN; writel(con, ®->tmu_control); - /* LEV0 LEV1 LEV2 interrupt enable */ - writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2, ®->inten); + /* Enable HW thermal trip */ + set_hw_thermal_trip(); + + /* LEV1 LEV2 interrupt enable */ + writel(INTEN_RISE1 | INTEN_RISE2, ®->inten); } /* -- cgit v1.1 From 871333fcfe3b0865f37a803e010f7b06d6e546f2 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:07 +0000 Subject: Exynos5: FDT: Add a H/W-trip member to TMU node This adds a member to TMU FDT node for providing hardware tripping temperature threshold. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/dts/exynos5250-smdk5250.dts | 1 + doc/device-tree-bindings/exynos/tmu.txt | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 00dac40..1c2d52d 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -72,6 +72,7 @@ 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>; diff --git a/doc/device-tree-bindings/exynos/tmu.txt b/doc/device-tree-bindings/exynos/tmu.txt index bb734dc..89d3bf0 100644 --- a/doc/device-tree-bindings/exynos/tmu.txt +++ b/doc/device-tree-bindings/exynos/tmu.txt @@ -8,7 +8,9 @@ Required properties: - 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 system will trip and shutdown (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) @@ -33,6 +35,7 @@ tmu@10060000 { 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>; -- cgit v1.1 From 2881e533472bffbf7cfa3afedb05b18cca574648 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 28 Feb 2013 01:40:41 +0000 Subject: EXYNOS5: Add initial DTS file for Snow. This patch adds the DTS file for Snow Board. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/dts/exynos5250-snow.dts | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 board/samsung/dts/exynos5250-snow.dts diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts new file mode 100644 index 0000000..8b303bf --- /dev/null +++ b/board/samsung/dts/exynos5250-snow.dts @@ -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"; + }; + }; +}; -- cgit v1.1 From d4ea072ca633d3acb9b74281f05fc30a7e6cda73 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 28 Feb 2013 01:40:42 +0000 Subject: EXYNOS5: Snow: Add a configuration file This patch adds the configuration file for Snow Board and defines the same in boards.cfg. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- MAINTAINERS | 4 ++++ boards.cfg | 1 + include/configs/snow.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 include/configs/snow.h diff --git a/MAINTAINERS b/MAINTAINERS index 45e2dd4..f6723ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -910,6 +910,10 @@ Matt Sealey Bo Shen at91sam9x5ek ARM926EJS (AT91SAM9G15,G25,G35,X25,X35 SoC) +Rajeshwari Shinde + + snow ARM ARMV7 (EXYNOS5250 SoC) + Michal Simek zynq ARM ARMV7 (Zynq SoC) diff --git a/boards.cfg b/boards.cfg index b1319aa..54357eb 100644 --- a/boards.cfg +++ b/boards.cfg @@ -286,6 +286,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 diff --git a/include/configs/snow.h b/include/configs/snow.h new file mode 100644 index 0000000..b8460fd --- /dev/null +++ b/include/configs/snow.h @@ -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 + +#undef CONFIG_DEFAULT_DEVICE_TREE +#define CONFIG_DEFAULT_DEVICE_TREE exynos5250-snow + +#endif /* __CONFIG_SNOW_H */ -- cgit v1.1 From ce0c1bc13556fbf1bdfa2a4a27ca6744e7beb32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Majewski?= Date: Fri, 11 Jan 2013 05:08:54 +0000 Subject: mmc:sdhci:fix: Change default interrupts enabled at SDHCI initialization This patch changes sdhci_init()'s behavior to NOT enable all interrupt sources by default. Moreover interrupt signaling has been disabled. This patch do not enable interrupts which aren't served in u-boot (they are defined at sdhci.h but NOT used elsewhere): - SDHCI_INT_CARD_INSERT, SDHCI_INT_CARD_REMOVE, SDHCI_BUS_POWER, SDHCI_INT_CARD_REMOVE, SDHCI_INT_CARD_INT Special care shall be put on SDHCI_INT_CARD_INT, which indicates interrupt generated by SD card. According to "SD Host Controller Simplified Spec. ver 3.00" when bit 8 (Card Interrupt Status Enable) at "Normal Interrupt Status Enable Register" (offset 0x34) is set, the card interrupt detection is started. Then eMMC card may cause the SD controller to set this bit and then this interrupt is passed to booted OS and might cause kernel crash. To sum up: - Only enable interrupts, which are served at u-boot - This cleanup as a side effect fixes SDHCI's CARD INTERRUPT problem at Linux kernel (versions 3.6+, sdhci controller) - Keep masked bits at "Normal Interrupt Signal Enable Register" (0x38h) Signed-off-by: Lukasz Majewski Signed-off-by: Kyungmin Park Cc: Lei Wen Cc: Andy Fleming Acked-by: Jaehoon Chung Signed-off-by: Minkyu Kang --- drivers/mmc/sdhci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index b9cbe34..551b423 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -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; } -- cgit v1.1