11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2b07682b6SSantosh Shilimkar /* 3fc7b92fcSBalaji T K * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM 4fc7b92fcSBalaji T K * and audio CODEC devices 5b07682b6SSantosh Shilimkar * 6b07682b6SSantosh Shilimkar * Copyright (C) 2005-2006 Texas Instruments, Inc. 7b07682b6SSantosh Shilimkar * 8b07682b6SSantosh Shilimkar * Modifications to defer interrupt handling to a kernel thread: 9b07682b6SSantosh Shilimkar * Copyright (C) 2006 MontaVista Software, Inc. 10b07682b6SSantosh Shilimkar * 11b07682b6SSantosh Shilimkar * Based on tlv320aic23.c: 12b07682b6SSantosh Shilimkar * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> 13b07682b6SSantosh Shilimkar * 14b07682b6SSantosh Shilimkar * Code cleanup and modifications to IRQ handler. 15b07682b6SSantosh Shilimkar * by syed khasim <x0khasim@ti.com> 16b07682b6SSantosh Shilimkar */ 17b07682b6SSantosh Shilimkar 18b07682b6SSantosh Shilimkar #include <linux/init.h> 19b07682b6SSantosh Shilimkar #include <linux/mutex.h> 20b07682b6SSantosh Shilimkar #include <linux/platform_device.h> 212473d25aSPeter Ujfalusi #include <linux/regmap.h> 22b07682b6SSantosh Shilimkar #include <linux/clk.h> 23b07682b6SSantosh Shilimkar #include <linux/err.h> 24aeb5032bSBenoit Cousson #include <linux/device.h> 25aeb5032bSBenoit Cousson #include <linux/of.h> 26aeb5032bSBenoit Cousson #include <linux/of_irq.h> 27aeb5032bSBenoit Cousson #include <linux/of_platform.h> 28e7cc3acaSGrant Likely #include <linux/irq.h> 29aeb5032bSBenoit Cousson #include <linux/irqdomain.h> 30b07682b6SSantosh Shilimkar 31b07682b6SSantosh Shilimkar #include <linux/regulator/machine.h> 32b07682b6SSantosh Shilimkar 33b07682b6SSantosh Shilimkar #include <linux/i2c.h> 34a2054256SWolfram Sang #include <linux/mfd/twl.h> 35b07682b6SSantosh Shilimkar 3691460700SPeter Ujfalusi /* Register descriptions for audio */ 3791460700SPeter Ujfalusi #include <linux/mfd/twl4030-audio.h> 3891460700SPeter Ujfalusi 391b8f333fSBenoit Cousson #include "twl-core.h" 40b07682b6SSantosh Shilimkar 41b07682b6SSantosh Shilimkar /* 42b07682b6SSantosh Shilimkar * The TWL4030 "Triton 2" is one of a family of a multi-function "Power 43b07682b6SSantosh Shilimkar * Management and System Companion Device" chips originally designed for 44b07682b6SSantosh Shilimkar * use in OMAP2 and OMAP 3 based systems. Its control interfaces use I2C, 45b07682b6SSantosh Shilimkar * often at around 3 Mbit/sec, including for interrupt handling. 46b07682b6SSantosh Shilimkar * 47b07682b6SSantosh Shilimkar * This driver core provides genirq support for the interrupts emitted, 48b07682b6SSantosh Shilimkar * by the various modules, and exports register access primitives. 49b07682b6SSantosh Shilimkar * 50b07682b6SSantosh Shilimkar * FIXME this driver currently requires use of the first interrupt line 51b07682b6SSantosh Shilimkar * (and associated registers). 52b07682b6SSantosh Shilimkar */ 53b07682b6SSantosh Shilimkar 54fc7b92fcSBalaji T K #define DRIVER_NAME "twl" 55b07682b6SSantosh Shilimkar 56b07682b6SSantosh Shilimkar /* Triton Core internal information (BEGIN) */ 57b07682b6SSantosh Shilimkar 58b07682b6SSantosh Shilimkar /* Base Address defns for twl4030_map[] */ 59b07682b6SSantosh Shilimkar 60b07682b6SSantosh Shilimkar /* subchip/slave 0 - USB ID */ 61b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_USB 0x0000 62b07682b6SSantosh Shilimkar 63b07682b6SSantosh Shilimkar /* subchip/slave 1 - AUD ID */ 64b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_AUDIO_VOICE 0x0000 65b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_GPIO 0x0098 66b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INTBR 0x0085 67b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PIH 0x0080 68b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_TEST 0x004C 69b07682b6SSantosh Shilimkar 70b07682b6SSantosh Shilimkar /* subchip/slave 2 - AUX ID */ 71b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INTERRUPTS 0x00B9 72b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_LED 0x00EE 73b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_MADC 0x0000 74b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_MAIN_CHARGE 0x0074 75b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PRECHARGE 0x00AA 765d4e9bd7SPeter Ujfalusi #define TWL4030_BASEADD_PWM 0x00F8 77b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_KEYPAD 0x00D2 78b07682b6SSantosh Shilimkar 79b07682b6SSantosh Shilimkar #define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */ 80b07682b6SSantosh Shilimkar #define TWL5031_BASEADD_INTERRUPTS 0x00B9 /* Different than TWL4030's 81b07682b6SSantosh Shilimkar one */ 82b07682b6SSantosh Shilimkar 83b07682b6SSantosh Shilimkar /* subchip/slave 3 - POWER ID */ 84b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_BACKUP 0x0014 85b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INT 0x002E 86b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PM_MASTER 0x0036 87a613b739STony Lindgren 88b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PM_RECEIVER 0x005B 89a613b739STony Lindgren #define TWL4030_DCDC_GLOBAL_CFG 0x06 90a613b739STony Lindgren #define SMARTREFLEX_ENABLE BIT(3) 91a613b739STony Lindgren 92b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_RTC 0x001C 93b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_SECURED_REG 0x0000 94b07682b6SSantosh Shilimkar 95b07682b6SSantosh Shilimkar /* Triton Core internal information (END) */ 96b07682b6SSantosh Shilimkar 97b07682b6SSantosh Shilimkar 98e8deb28cSBalaji T K /* subchip/slave 0 0x48 - POWER */ 99e8deb28cSBalaji T K #define TWL6030_BASEADD_RTC 0x0000 1005d4e9bd7SPeter Ujfalusi #define TWL6030_BASEADD_SECURED_REG 0x0017 101e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_MASTER 0x001F 102e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ 103e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_MISC 0x00E2 104e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_PUPD 0x00F0 105e8deb28cSBalaji T K 106e8deb28cSBalaji T K /* subchip/slave 1 0x49 - FEATURE */ 107e8deb28cSBalaji T K #define TWL6030_BASEADD_USB 0x0000 108e8deb28cSBalaji T K #define TWL6030_BASEADD_GPADC_CTRL 0x002E 109e8deb28cSBalaji T K #define TWL6030_BASEADD_AUX 0x0090 110e8deb28cSBalaji T K #define TWL6030_BASEADD_PWM 0x00BA 111e8deb28cSBalaji T K #define TWL6030_BASEADD_GASGAUGE 0x00C0 112e8deb28cSBalaji T K #define TWL6030_BASEADD_PIH 0x00D0 113e8deb28cSBalaji T K #define TWL6030_BASEADD_CHARGER 0x00E0 11489ce43fbSGraeme Gregory #define TWL6032_BASEADD_CHARGER 0x00DA 1155d4e9bd7SPeter Ujfalusi #define TWL6030_BASEADD_LED 0x00F4 116e8deb28cSBalaji T K 117e8deb28cSBalaji T K /* subchip/slave 2 0x4A - DFT */ 118e8deb28cSBalaji T K #define TWL6030_BASEADD_DIEID 0x00C0 119e8deb28cSBalaji T K 120e8deb28cSBalaji T K /* subchip/slave 3 0x4B - AUDIO */ 121e8deb28cSBalaji T K #define TWL6030_BASEADD_AUDIO 0x0000 122e8deb28cSBalaji T K #define TWL6030_BASEADD_RSV 0x0000 123fa0d9762SBalaji T K #define TWL6030_BASEADD_ZERO 0x0000 124e8deb28cSBalaji T K 125b07682b6SSantosh Shilimkar /* Few power values */ 126b07682b6SSantosh Shilimkar #define R_CFG_BOOT 0x05 127b07682b6SSantosh Shilimkar 128b07682b6SSantosh Shilimkar /* some fields in R_CFG_BOOT */ 129b07682b6SSantosh Shilimkar #define HFCLK_FREQ_19p2_MHZ (1 << 0) 130b07682b6SSantosh Shilimkar #define HFCLK_FREQ_26_MHZ (2 << 0) 131b07682b6SSantosh Shilimkar #define HFCLK_FREQ_38p4_MHZ (3 << 0) 132b07682b6SSantosh Shilimkar #define HIGH_PERF_SQ (1 << 3) 133b07682b6SSantosh Shilimkar #define CK32K_LOWPWR_EN (1 << 7) 134b07682b6SSantosh Shilimkar 135b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 136b07682b6SSantosh Shilimkar 137e8deb28cSBalaji T K /* Structure for each TWL4030/TWL6030 Slave */ 138fc7b92fcSBalaji T K struct twl_client { 139b07682b6SSantosh Shilimkar struct i2c_client *client; 1402473d25aSPeter Ujfalusi struct regmap *regmap; 141b07682b6SSantosh Shilimkar }; 142b07682b6SSantosh Shilimkar 143b07682b6SSantosh Shilimkar /* mapping the module id to slave id and base address */ 144fc7b92fcSBalaji T K struct twl_mapping { 145b07682b6SSantosh Shilimkar unsigned char sid; /* Slave ID */ 146b07682b6SSantosh Shilimkar unsigned char base; /* base address */ 147b07682b6SSantosh Shilimkar }; 14880a97ccdSPeter Ujfalusi 14980a97ccdSPeter Ujfalusi struct twl_private { 15080a97ccdSPeter Ujfalusi bool ready; /* The core driver is ready to be used */ 15180a97ccdSPeter Ujfalusi u32 twl_idcode; /* TWL IDCODE Register value */ 15280a97ccdSPeter Ujfalusi unsigned int twl_id; 15380a97ccdSPeter Ujfalusi 15480a97ccdSPeter Ujfalusi struct twl_mapping *twl_map; 15580a97ccdSPeter Ujfalusi struct twl_client *twl_modules; 15680a97ccdSPeter Ujfalusi }; 15780a97ccdSPeter Ujfalusi 15880a97ccdSPeter Ujfalusi static struct twl_private *twl_priv; 159b07682b6SSantosh Shilimkar 160da059ecfSPeter Ujfalusi static struct twl_mapping twl4030_map[] = { 161b07682b6SSantosh Shilimkar /* 162b07682b6SSantosh Shilimkar * NOTE: don't change this table without updating the 163a2054256SWolfram Sang * <linux/mfd/twl.h> defines for TWL4030_MODULE_* 164b07682b6SSantosh Shilimkar * so they continue to match the order in this table. 165b07682b6SSantosh Shilimkar */ 166b07682b6SSantosh Shilimkar 1675d4e9bd7SPeter Ujfalusi /* Common IPs */ 168b07682b6SSantosh Shilimkar { 0, TWL4030_BASEADD_USB }, 1695d4e9bd7SPeter Ujfalusi { 1, TWL4030_BASEADD_PIH }, 1705d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_MAIN_CHARGE }, 1715d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_PM_MASTER }, 1725d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_PM_RECEIVER }, 1735d4e9bd7SPeter Ujfalusi 1745d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_RTC }, 1755d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_PWM }, 1765d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_LED }, 1775d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_SECURED_REG }, 1785d4e9bd7SPeter Ujfalusi 1795d4e9bd7SPeter Ujfalusi /* TWL4030 specific IPs */ 180b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_AUDIO_VOICE }, 181b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_GPIO }, 182b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_INTBR }, 1836691ccd0SPeter Ujfalusi { 1, TWL4030_BASEADD_TEST }, 184b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_KEYPAD }, 1855d4e9bd7SPeter Ujfalusi 186b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_MADC }, 187b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_INTERRUPTS }, 188b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_PRECHARGE }, 189b07682b6SSantosh Shilimkar { 3, TWL4030_BASEADD_BACKUP }, 190b07682b6SSantosh Shilimkar { 3, TWL4030_BASEADD_INT }, 1916691ccd0SPeter Ujfalusi 1925d4e9bd7SPeter Ujfalusi { 2, TWL5031_BASEADD_ACCESSORY }, 1935d4e9bd7SPeter Ujfalusi { 2, TWL5031_BASEADD_INTERRUPTS }, 194b07682b6SSantosh Shilimkar }; 195b07682b6SSantosh Shilimkar 196d842b61bSKrzysztof Kozlowski static const struct reg_default twl4030_49_defaults[] = { 19791460700SPeter Ujfalusi /* Audio Registers */ 19891460700SPeter Ujfalusi { 0x01, 0x00}, /* CODEC_MODE */ 19991460700SPeter Ujfalusi { 0x02, 0x00}, /* OPTION */ 20091460700SPeter Ujfalusi /* 0x03 Unused */ 20191460700SPeter Ujfalusi { 0x04, 0x00}, /* MICBIAS_CTL */ 20291460700SPeter Ujfalusi { 0x05, 0x00}, /* ANAMICL */ 20391460700SPeter Ujfalusi { 0x06, 0x00}, /* ANAMICR */ 20491460700SPeter Ujfalusi { 0x07, 0x00}, /* AVADC_CTL */ 20591460700SPeter Ujfalusi { 0x08, 0x00}, /* ADCMICSEL */ 20691460700SPeter Ujfalusi { 0x09, 0x00}, /* DIGMIXING */ 20791460700SPeter Ujfalusi { 0x0a, 0x0f}, /* ATXL1PGA */ 20891460700SPeter Ujfalusi { 0x0b, 0x0f}, /* ATXR1PGA */ 20991460700SPeter Ujfalusi { 0x0c, 0x0f}, /* AVTXL2PGA */ 21091460700SPeter Ujfalusi { 0x0d, 0x0f}, /* AVTXR2PGA */ 21191460700SPeter Ujfalusi { 0x0e, 0x00}, /* AUDIO_IF */ 21291460700SPeter Ujfalusi { 0x0f, 0x00}, /* VOICE_IF */ 21391460700SPeter Ujfalusi { 0x10, 0x3f}, /* ARXR1PGA */ 21491460700SPeter Ujfalusi { 0x11, 0x3f}, /* ARXL1PGA */ 21591460700SPeter Ujfalusi { 0x12, 0x3f}, /* ARXR2PGA */ 21691460700SPeter Ujfalusi { 0x13, 0x3f}, /* ARXL2PGA */ 21791460700SPeter Ujfalusi { 0x14, 0x25}, /* VRXPGA */ 21891460700SPeter Ujfalusi { 0x15, 0x00}, /* VSTPGA */ 21991460700SPeter Ujfalusi { 0x16, 0x00}, /* VRX2ARXPGA */ 22091460700SPeter Ujfalusi { 0x17, 0x00}, /* AVDAC_CTL */ 22191460700SPeter Ujfalusi { 0x18, 0x00}, /* ARX2VTXPGA */ 22291460700SPeter Ujfalusi { 0x19, 0x32}, /* ARXL1_APGA_CTL*/ 22391460700SPeter Ujfalusi { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/ 22491460700SPeter Ujfalusi { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/ 22591460700SPeter Ujfalusi { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/ 22691460700SPeter Ujfalusi { 0x1d, 0x00}, /* ATX2ARXPGA */ 22791460700SPeter Ujfalusi { 0x1e, 0x00}, /* BT_IF */ 22891460700SPeter Ujfalusi { 0x1f, 0x55}, /* BTPGA */ 22991460700SPeter Ujfalusi { 0x20, 0x00}, /* BTSTPGA */ 23091460700SPeter Ujfalusi { 0x21, 0x00}, /* EAR_CTL */ 23191460700SPeter Ujfalusi { 0x22, 0x00}, /* HS_SEL */ 23291460700SPeter Ujfalusi { 0x23, 0x00}, /* HS_GAIN_SET */ 23391460700SPeter Ujfalusi { 0x24, 0x00}, /* HS_POPN_SET */ 23491460700SPeter Ujfalusi { 0x25, 0x00}, /* PREDL_CTL */ 23591460700SPeter Ujfalusi { 0x26, 0x00}, /* PREDR_CTL */ 23691460700SPeter Ujfalusi { 0x27, 0x00}, /* PRECKL_CTL */ 23791460700SPeter Ujfalusi { 0x28, 0x00}, /* PRECKR_CTL */ 23891460700SPeter Ujfalusi { 0x29, 0x00}, /* HFL_CTL */ 23991460700SPeter Ujfalusi { 0x2a, 0x00}, /* HFR_CTL */ 24091460700SPeter Ujfalusi { 0x2b, 0x05}, /* ALC_CTL */ 24191460700SPeter Ujfalusi { 0x2c, 0x00}, /* ALC_SET1 */ 24291460700SPeter Ujfalusi { 0x2d, 0x00}, /* ALC_SET2 */ 24391460700SPeter Ujfalusi { 0x2e, 0x00}, /* BOOST_CTL */ 24491460700SPeter Ujfalusi { 0x2f, 0x00}, /* SOFTVOL_CTL */ 24591460700SPeter Ujfalusi { 0x30, 0x13}, /* DTMF_FREQSEL */ 24691460700SPeter Ujfalusi { 0x31, 0x00}, /* DTMF_TONEXT1H */ 24791460700SPeter Ujfalusi { 0x32, 0x00}, /* DTMF_TONEXT1L */ 24891460700SPeter Ujfalusi { 0x33, 0x00}, /* DTMF_TONEXT2H */ 24991460700SPeter Ujfalusi { 0x34, 0x00}, /* DTMF_TONEXT2L */ 25091460700SPeter Ujfalusi { 0x35, 0x79}, /* DTMF_TONOFF */ 25191460700SPeter Ujfalusi { 0x36, 0x11}, /* DTMF_WANONOFF */ 25291460700SPeter Ujfalusi { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */ 25391460700SPeter Ujfalusi { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */ 25491460700SPeter Ujfalusi { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */ 25591460700SPeter Ujfalusi { 0x3a, 0x06}, /* APLL_CTL */ 25691460700SPeter Ujfalusi { 0x3b, 0x00}, /* DTMF_CTL */ 25791460700SPeter Ujfalusi { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */ 25891460700SPeter Ujfalusi { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */ 25991460700SPeter Ujfalusi { 0x3e, 0x00}, /* MISC_SET_1 */ 26091460700SPeter Ujfalusi { 0x3f, 0x00}, /* PCMBTMUX */ 26191460700SPeter Ujfalusi /* 0x40 - 0x42 Unused */ 26291460700SPeter Ujfalusi { 0x43, 0x00}, /* RX_PATH_SEL */ 26391460700SPeter Ujfalusi { 0x44, 0x32}, /* VDL_APGA_CTL */ 26491460700SPeter Ujfalusi { 0x45, 0x00}, /* VIBRA_CTL */ 26591460700SPeter Ujfalusi { 0x46, 0x00}, /* VIBRA_SET */ 26691460700SPeter Ujfalusi { 0x47, 0x00}, /* VIBRA_PWM_SET */ 26791460700SPeter Ujfalusi { 0x48, 0x00}, /* ANAMIC_GAIN */ 26891460700SPeter Ujfalusi { 0x49, 0x00}, /* MISC_SET_2 */ 26991460700SPeter Ujfalusi /* End of Audio Registers */ 27091460700SPeter Ujfalusi }; 27191460700SPeter Ujfalusi 27291460700SPeter Ujfalusi static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg) 27391460700SPeter Ujfalusi { 27491460700SPeter Ujfalusi switch (reg) { 27556816b70STomas Novotny case 0x00: 27656816b70STomas Novotny case 0x03: 27756816b70STomas Novotny case 0x40: 27856816b70STomas Novotny case 0x41: 27956816b70STomas Novotny case 0x42: 28091460700SPeter Ujfalusi return false; 28191460700SPeter Ujfalusi default: 28291460700SPeter Ujfalusi return true; 28391460700SPeter Ujfalusi } 28491460700SPeter Ujfalusi } 28591460700SPeter Ujfalusi 28691460700SPeter Ujfalusi static const struct regmap_range twl4030_49_volatile_ranges[] = { 28791460700SPeter Ujfalusi regmap_reg_range(TWL4030_BASEADD_TEST, 0xff), 28891460700SPeter Ujfalusi }; 28991460700SPeter Ujfalusi 29091460700SPeter Ujfalusi static const struct regmap_access_table twl4030_49_volatile_table = { 29191460700SPeter Ujfalusi .yes_ranges = twl4030_49_volatile_ranges, 29291460700SPeter Ujfalusi .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges), 29391460700SPeter Ujfalusi }; 29491460700SPeter Ujfalusi 295d842b61bSKrzysztof Kozlowski static const struct regmap_config twl4030_regmap_config[4] = { 2962473d25aSPeter Ujfalusi { 2972473d25aSPeter Ujfalusi /* Address 0x48 */ 2982473d25aSPeter Ujfalusi .reg_bits = 8, 2992473d25aSPeter Ujfalusi .val_bits = 8, 3002473d25aSPeter Ujfalusi .max_register = 0xff, 3012473d25aSPeter Ujfalusi }, 3022473d25aSPeter Ujfalusi { 3032473d25aSPeter Ujfalusi /* Address 0x49 */ 3042473d25aSPeter Ujfalusi .reg_bits = 8, 3052473d25aSPeter Ujfalusi .val_bits = 8, 3062473d25aSPeter Ujfalusi .max_register = 0xff, 30791460700SPeter Ujfalusi 30891460700SPeter Ujfalusi .readable_reg = twl4030_49_nop_reg, 30991460700SPeter Ujfalusi .writeable_reg = twl4030_49_nop_reg, 31091460700SPeter Ujfalusi 31191460700SPeter Ujfalusi .volatile_table = &twl4030_49_volatile_table, 31291460700SPeter Ujfalusi 31391460700SPeter Ujfalusi .reg_defaults = twl4030_49_defaults, 31491460700SPeter Ujfalusi .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), 31591460700SPeter Ujfalusi .cache_type = REGCACHE_RBTREE, 3162473d25aSPeter Ujfalusi }, 3172473d25aSPeter Ujfalusi { 3182473d25aSPeter Ujfalusi /* Address 0x4a */ 3192473d25aSPeter Ujfalusi .reg_bits = 8, 3202473d25aSPeter Ujfalusi .val_bits = 8, 3212473d25aSPeter Ujfalusi .max_register = 0xff, 3222473d25aSPeter Ujfalusi }, 3232473d25aSPeter Ujfalusi { 3242473d25aSPeter Ujfalusi /* Address 0x4b */ 3252473d25aSPeter Ujfalusi .reg_bits = 8, 3262473d25aSPeter Ujfalusi .val_bits = 8, 3272473d25aSPeter Ujfalusi .max_register = 0xff, 3282473d25aSPeter Ujfalusi }, 3292473d25aSPeter Ujfalusi }; 3302473d25aSPeter Ujfalusi 331e8deb28cSBalaji T K static struct twl_mapping twl6030_map[] = { 332e8deb28cSBalaji T K /* 333e8deb28cSBalaji T K * NOTE: don't change this table without updating the 334a2054256SWolfram Sang * <linux/mfd/twl.h> defines for TWL4030_MODULE_* 335e8deb28cSBalaji T K * so they continue to match the order in this table. 336e8deb28cSBalaji T K */ 337e8deb28cSBalaji T K 3385d4e9bd7SPeter Ujfalusi /* Common IPs */ 3395d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_USB }, 3405d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_PIH }, 3415d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_CHARGER }, 3425d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_PM_MASTER }, 3435d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_PM_SLAVE_MISC }, 344e8deb28cSBalaji T K 3455d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_RTC }, 3465d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_PWM }, 3475d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_LED }, 3485d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_SECURED_REG }, 349e8deb28cSBalaji T K 3505d4e9bd7SPeter Ujfalusi /* TWL6030 specific IPs */ 3515d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_ZERO }, 3525d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_ZERO }, 3535d4e9bd7SPeter Ujfalusi { 2, TWL6030_BASEADD_ZERO }, 3545d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_GPADC_CTRL }, 3555d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_GASGAUGE }, 356e8deb28cSBalaji T K }; 357e8deb28cSBalaji T K 358d842b61bSKrzysztof Kozlowski static const struct regmap_config twl6030_regmap_config[3] = { 3592473d25aSPeter Ujfalusi { 3602473d25aSPeter Ujfalusi /* Address 0x48 */ 3612473d25aSPeter Ujfalusi .reg_bits = 8, 3622473d25aSPeter Ujfalusi .val_bits = 8, 3632473d25aSPeter Ujfalusi .max_register = 0xff, 3642473d25aSPeter Ujfalusi }, 3652473d25aSPeter Ujfalusi { 3662473d25aSPeter Ujfalusi /* Address 0x49 */ 3672473d25aSPeter Ujfalusi .reg_bits = 8, 3682473d25aSPeter Ujfalusi .val_bits = 8, 3692473d25aSPeter Ujfalusi .max_register = 0xff, 3702473d25aSPeter Ujfalusi }, 3712473d25aSPeter Ujfalusi { 3722473d25aSPeter Ujfalusi /* Address 0x4a */ 3732473d25aSPeter Ujfalusi .reg_bits = 8, 3742473d25aSPeter Ujfalusi .val_bits = 8, 3752473d25aSPeter Ujfalusi .max_register = 0xff, 3762473d25aSPeter Ujfalusi }, 3772473d25aSPeter Ujfalusi }; 3782473d25aSPeter Ujfalusi 379b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 380b07682b6SSantosh Shilimkar 3816dd810b5SPeter Ujfalusi static inline int twl_get_num_slaves(void) 3826dd810b5SPeter Ujfalusi { 3836dd810b5SPeter Ujfalusi if (twl_class_is_4030()) 3846dd810b5SPeter Ujfalusi return 4; /* TWL4030 class have four slave address */ 3856dd810b5SPeter Ujfalusi else 3866dd810b5SPeter Ujfalusi return 3; /* TWL6030 class have three slave address */ 3876dd810b5SPeter Ujfalusi } 3886dd810b5SPeter Ujfalusi 3895d4e9bd7SPeter Ujfalusi static inline int twl_get_last_module(void) 3905d4e9bd7SPeter Ujfalusi { 3915d4e9bd7SPeter Ujfalusi if (twl_class_is_4030()) 3925d4e9bd7SPeter Ujfalusi return TWL4030_MODULE_LAST; 3935d4e9bd7SPeter Ujfalusi else 3945d4e9bd7SPeter Ujfalusi return TWL6030_MODULE_LAST; 3955d4e9bd7SPeter Ujfalusi } 3965d4e9bd7SPeter Ujfalusi 397b07682b6SSantosh Shilimkar /* Exported Functions */ 398b07682b6SSantosh Shilimkar 39980a97ccdSPeter Ujfalusi unsigned int twl_rev(void) 40080a97ccdSPeter Ujfalusi { 40180a97ccdSPeter Ujfalusi return twl_priv ? twl_priv->twl_id : 0; 40280a97ccdSPeter Ujfalusi } 40380a97ccdSPeter Ujfalusi EXPORT_SYMBOL(twl_rev); 40480a97ccdSPeter Ujfalusi 405b07682b6SSantosh Shilimkar /** 4068daf3540SPeter Ujfalusi * twl_get_regmap - Get the regmap associated with the given module 4078daf3540SPeter Ujfalusi * @mod_no: module number 4088daf3540SPeter Ujfalusi * 4098daf3540SPeter Ujfalusi * Returns the regmap pointer or NULL in case of failure. 4108daf3540SPeter Ujfalusi */ 4118daf3540SPeter Ujfalusi static struct regmap *twl_get_regmap(u8 mod_no) 4128daf3540SPeter Ujfalusi { 4138daf3540SPeter Ujfalusi int sid; 4148daf3540SPeter Ujfalusi struct twl_client *twl; 4158daf3540SPeter Ujfalusi 4168daf3540SPeter Ujfalusi if (unlikely(!twl_priv || !twl_priv->ready)) { 4178daf3540SPeter Ujfalusi pr_err("%s: not initialized\n", DRIVER_NAME); 4188daf3540SPeter Ujfalusi return NULL; 4198daf3540SPeter Ujfalusi } 4208daf3540SPeter Ujfalusi if (unlikely(mod_no >= twl_get_last_module())) { 4218daf3540SPeter Ujfalusi pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); 4228daf3540SPeter Ujfalusi return NULL; 4238daf3540SPeter Ujfalusi } 4248daf3540SPeter Ujfalusi 4258daf3540SPeter Ujfalusi sid = twl_priv->twl_map[mod_no].sid; 4268daf3540SPeter Ujfalusi twl = &twl_priv->twl_modules[sid]; 4278daf3540SPeter Ujfalusi 4288daf3540SPeter Ujfalusi return twl->regmap; 4298daf3540SPeter Ujfalusi } 4308daf3540SPeter Ujfalusi 4318daf3540SPeter Ujfalusi /** 432fc7b92fcSBalaji T K * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 433b07682b6SSantosh Shilimkar * @mod_no: module number 434b07682b6SSantosh Shilimkar * @value: an array of num_bytes+1 containing data to write 435b07682b6SSantosh Shilimkar * @reg: register address (just offset will do) 436b07682b6SSantosh Shilimkar * @num_bytes: number of bytes to transfer 437b07682b6SSantosh Shilimkar * 438ff827cf5SDan Carpenter * Returns 0 on success or else a negative error code. 439b07682b6SSantosh Shilimkar */ 440fc7b92fcSBalaji T K int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 441b07682b6SSantosh Shilimkar { 4428daf3540SPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 443b07682b6SSantosh Shilimkar int ret; 444b07682b6SSantosh Shilimkar 4458daf3540SPeter Ujfalusi if (!regmap) 446b07682b6SSantosh Shilimkar return -EPERM; 447050cde13SPeter Ujfalusi 4488daf3540SPeter Ujfalusi ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg, 4498daf3540SPeter Ujfalusi value, num_bytes); 450b07682b6SSantosh Shilimkar 4512473d25aSPeter Ujfalusi if (ret) 4522473d25aSPeter Ujfalusi pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", 4532473d25aSPeter Ujfalusi DRIVER_NAME, mod_no, reg, num_bytes); 4542473d25aSPeter Ujfalusi 455b07682b6SSantosh Shilimkar return ret; 456b07682b6SSantosh Shilimkar } 457fc7b92fcSBalaji T K EXPORT_SYMBOL(twl_i2c_write); 458b07682b6SSantosh Shilimkar 459b07682b6SSantosh Shilimkar /** 460fc7b92fcSBalaji T K * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0 461b07682b6SSantosh Shilimkar * @mod_no: module number 462b07682b6SSantosh Shilimkar * @value: an array of num_bytes containing data to be read 463b07682b6SSantosh Shilimkar * @reg: register address (just offset will do) 464b07682b6SSantosh Shilimkar * @num_bytes: number of bytes to transfer 465b07682b6SSantosh Shilimkar * 466ff827cf5SDan Carpenter * Returns 0 on success or else a negative error code. 467b07682b6SSantosh Shilimkar */ 468fc7b92fcSBalaji T K int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 469b07682b6SSantosh Shilimkar { 4708daf3540SPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 471b07682b6SSantosh Shilimkar int ret; 472b07682b6SSantosh Shilimkar 4738daf3540SPeter Ujfalusi if (!regmap) 474b07682b6SSantosh Shilimkar return -EPERM; 475050cde13SPeter Ujfalusi 4768daf3540SPeter Ujfalusi ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg, 4778daf3540SPeter Ujfalusi value, num_bytes); 478b07682b6SSantosh Shilimkar 4792473d25aSPeter Ujfalusi if (ret) 4802473d25aSPeter Ujfalusi pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n", 4812473d25aSPeter Ujfalusi DRIVER_NAME, mod_no, reg, num_bytes); 4822473d25aSPeter Ujfalusi 483b07682b6SSantosh Shilimkar return ret; 484b07682b6SSantosh Shilimkar } 485fc7b92fcSBalaji T K EXPORT_SYMBOL(twl_i2c_read); 486b07682b6SSantosh Shilimkar 4873def927eSPeter Ujfalusi /** 4889b31ec3dSLee Jones * twl_set_regcache_bypass - Configure the regcache bypass for the regmap associated 4893def927eSPeter Ujfalusi * with the module 4903def927eSPeter Ujfalusi * @mod_no: module number 4913def927eSPeter Ujfalusi * @enable: Regcache bypass state 4923def927eSPeter Ujfalusi * 4933def927eSPeter Ujfalusi * Returns 0 else failure. 4943def927eSPeter Ujfalusi */ 4953def927eSPeter Ujfalusi int twl_set_regcache_bypass(u8 mod_no, bool enable) 4963def927eSPeter Ujfalusi { 4973def927eSPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 4983def927eSPeter Ujfalusi 4993def927eSPeter Ujfalusi if (!regmap) 5003def927eSPeter Ujfalusi return -EPERM; 5013def927eSPeter Ujfalusi 5023def927eSPeter Ujfalusi regcache_cache_bypass(regmap, enable); 5033def927eSPeter Ujfalusi 5043def927eSPeter Ujfalusi return 0; 5053def927eSPeter Ujfalusi } 5063def927eSPeter Ujfalusi EXPORT_SYMBOL(twl_set_regcache_bypass); 5073def927eSPeter Ujfalusi 508b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 509b07682b6SSantosh Shilimkar 510ca972d13SLesly A M /** 511ca972d13SLesly A M * twl_read_idcode_register - API to read the IDCODE register. 512ca972d13SLesly A M * 513ca972d13SLesly A M * Unlocks the IDCODE register and read the 32 bit value. 514ca972d13SLesly A M */ 515ca972d13SLesly A M static int twl_read_idcode_register(void) 516ca972d13SLesly A M { 517ca972d13SLesly A M int err; 518ca972d13SLesly A M 519ca972d13SLesly A M err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK, 520ca972d13SLesly A M REG_UNLOCK_TEST_REG); 521ca972d13SLesly A M if (err) { 522ca972d13SLesly A M pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err); 523ca972d13SLesly A M goto fail; 524ca972d13SLesly A M } 525ca972d13SLesly A M 52680a97ccdSPeter Ujfalusi err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode), 527ca972d13SLesly A M REG_IDCODE_7_0, 4); 528ca972d13SLesly A M if (err) { 529ca972d13SLesly A M pr_err("TWL4030: unable to read IDCODE -%d\n", err); 530ca972d13SLesly A M goto fail; 531ca972d13SLesly A M } 532ca972d13SLesly A M 533ca972d13SLesly A M err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG); 534ca972d13SLesly A M if (err) 535ca972d13SLesly A M pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err); 536ca972d13SLesly A M fail: 537ca972d13SLesly A M return err; 538ca972d13SLesly A M } 539ca972d13SLesly A M 540ca972d13SLesly A M /** 541ca972d13SLesly A M * twl_get_type - API to get TWL Si type. 542ca972d13SLesly A M * 543ca972d13SLesly A M * Api to get the TWL Si type from IDCODE value. 544ca972d13SLesly A M */ 545ca972d13SLesly A M int twl_get_type(void) 546ca972d13SLesly A M { 54780a97ccdSPeter Ujfalusi return TWL_SIL_TYPE(twl_priv->twl_idcode); 548ca972d13SLesly A M } 549ca972d13SLesly A M EXPORT_SYMBOL_GPL(twl_get_type); 550ca972d13SLesly A M 551ca972d13SLesly A M /** 552ca972d13SLesly A M * twl_get_version - API to get TWL Si version. 553ca972d13SLesly A M * 554ca972d13SLesly A M * Api to get the TWL Si version from IDCODE value. 555ca972d13SLesly A M */ 556ca972d13SLesly A M int twl_get_version(void) 557ca972d13SLesly A M { 55880a97ccdSPeter Ujfalusi return TWL_SIL_REV(twl_priv->twl_idcode); 559ca972d13SLesly A M } 560ca972d13SLesly A M EXPORT_SYMBOL_GPL(twl_get_version); 561ca972d13SLesly A M 5622275c544SPeter Ujfalusi /** 5632275c544SPeter Ujfalusi * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. 5642275c544SPeter Ujfalusi * 5652275c544SPeter Ujfalusi * Api to get the TWL HFCLK rate based on BOOT_CFG register. 5662275c544SPeter Ujfalusi */ 5672275c544SPeter Ujfalusi int twl_get_hfclk_rate(void) 5682275c544SPeter Ujfalusi { 5692275c544SPeter Ujfalusi u8 ctrl; 5702275c544SPeter Ujfalusi int rate; 5712275c544SPeter Ujfalusi 5722275c544SPeter Ujfalusi twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); 5732275c544SPeter Ujfalusi 5742275c544SPeter Ujfalusi switch (ctrl & 0x3) { 5752275c544SPeter Ujfalusi case HFCLK_FREQ_19p2_MHZ: 5762275c544SPeter Ujfalusi rate = 19200000; 5772275c544SPeter Ujfalusi break; 5782275c544SPeter Ujfalusi case HFCLK_FREQ_26_MHZ: 5792275c544SPeter Ujfalusi rate = 26000000; 5802275c544SPeter Ujfalusi break; 5812275c544SPeter Ujfalusi case HFCLK_FREQ_38p4_MHZ: 5822275c544SPeter Ujfalusi rate = 38400000; 5832275c544SPeter Ujfalusi break; 5842275c544SPeter Ujfalusi default: 5852275c544SPeter Ujfalusi pr_err("TWL4030: HFCLK is not configured\n"); 5862275c544SPeter Ujfalusi rate = -EINVAL; 5872275c544SPeter Ujfalusi break; 5882275c544SPeter Ujfalusi } 5892275c544SPeter Ujfalusi 5902275c544SPeter Ujfalusi return rate; 5912275c544SPeter Ujfalusi } 5922275c544SPeter Ujfalusi EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); 5932275c544SPeter Ujfalusi 594b07682b6SSantosh Shilimkar static struct device * 5953c330279SPeter Ujfalusi add_numbered_child(unsigned mod_no, const char *name, int num, 596b07682b6SSantosh Shilimkar void *pdata, unsigned pdata_len, 597b07682b6SSantosh Shilimkar bool can_wakeup, int irq0, int irq1) 598b07682b6SSantosh Shilimkar { 599b07682b6SSantosh Shilimkar struct platform_device *pdev; 6003c330279SPeter Ujfalusi struct twl_client *twl; 6013c330279SPeter Ujfalusi int status, sid; 6023c330279SPeter Ujfalusi 6033c330279SPeter Ujfalusi if (unlikely(mod_no >= twl_get_last_module())) { 6043c330279SPeter Ujfalusi pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); 6053c330279SPeter Ujfalusi return ERR_PTR(-EPERM); 6063c330279SPeter Ujfalusi } 60780a97ccdSPeter Ujfalusi sid = twl_priv->twl_map[mod_no].sid; 60880a97ccdSPeter Ujfalusi twl = &twl_priv->twl_modules[sid]; 609b07682b6SSantosh Shilimkar 610b07682b6SSantosh Shilimkar pdev = platform_device_alloc(name, num); 611a67911d3SMarkus Elfring if (!pdev) 612a67911d3SMarkus Elfring return ERR_PTR(-ENOMEM); 613b07682b6SSantosh Shilimkar 614b07682b6SSantosh Shilimkar pdev->dev.parent = &twl->client->dev; 615b07682b6SSantosh Shilimkar 616b07682b6SSantosh Shilimkar if (pdata) { 617b07682b6SSantosh Shilimkar status = platform_device_add_data(pdev, pdata, pdata_len); 618b07682b6SSantosh Shilimkar if (status < 0) { 619b07682b6SSantosh Shilimkar dev_dbg(&pdev->dev, "can't add platform_data\n"); 6208175a01cSMarkus Elfring goto put_device; 621b07682b6SSantosh Shilimkar } 622b07682b6SSantosh Shilimkar } 623b07682b6SSantosh Shilimkar 624b07682b6SSantosh Shilimkar if (irq0) { 625b07682b6SSantosh Shilimkar struct resource r[2] = { 626b07682b6SSantosh Shilimkar { .start = irq0, .flags = IORESOURCE_IRQ, }, 627b07682b6SSantosh Shilimkar { .start = irq1, .flags = IORESOURCE_IRQ, }, 628b07682b6SSantosh Shilimkar }; 629b07682b6SSantosh Shilimkar 630b07682b6SSantosh Shilimkar status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1); 631b07682b6SSantosh Shilimkar if (status < 0) { 632b07682b6SSantosh Shilimkar dev_dbg(&pdev->dev, "can't add irqs\n"); 6338175a01cSMarkus Elfring goto put_device; 634b07682b6SSantosh Shilimkar } 635b07682b6SSantosh Shilimkar } 636b07682b6SSantosh Shilimkar 637b07682b6SSantosh Shilimkar status = platform_device_add(pdev); 6388175a01cSMarkus Elfring if (status) 6398175a01cSMarkus Elfring goto put_device; 6408175a01cSMarkus Elfring 64117ffba6aSNeilBrown device_init_wakeup(&pdev->dev, can_wakeup); 642b07682b6SSantosh Shilimkar 643b07682b6SSantosh Shilimkar return &pdev->dev; 6448175a01cSMarkus Elfring 6458175a01cSMarkus Elfring put_device: 6468175a01cSMarkus Elfring platform_device_put(pdev); 6478175a01cSMarkus Elfring dev_err(&twl->client->dev, "failed to add device %s\n", name); 6488175a01cSMarkus Elfring return ERR_PTR(status); 649b07682b6SSantosh Shilimkar } 650b07682b6SSantosh Shilimkar 6513c330279SPeter Ujfalusi static inline struct device *add_child(unsigned mod_no, const char *name, 652b07682b6SSantosh Shilimkar void *pdata, unsigned pdata_len, 653b07682b6SSantosh Shilimkar bool can_wakeup, int irq0, int irq1) 654b07682b6SSantosh Shilimkar { 6553c330279SPeter Ujfalusi return add_numbered_child(mod_no, name, -1, pdata, pdata_len, 656b07682b6SSantosh Shilimkar can_wakeup, irq0, irq1); 657b07682b6SSantosh Shilimkar } 658b07682b6SSantosh Shilimkar 659b07682b6SSantosh Shilimkar static struct device * 660b07682b6SSantosh Shilimkar add_regulator_linked(int num, struct regulator_init_data *pdata, 661b07682b6SSantosh Shilimkar struct regulator_consumer_supply *consumers, 662521d8ec3SGraeme Gregory unsigned num_consumers, unsigned long features) 663b07682b6SSantosh Shilimkar { 66463bfff4eSTero Kristo struct twl_regulator_driver_data drv_data; 66563bfff4eSTero Kristo 666b07682b6SSantosh Shilimkar /* regulator framework demands init_data ... */ 667b07682b6SSantosh Shilimkar if (!pdata) 668b07682b6SSantosh Shilimkar return NULL; 669b07682b6SSantosh Shilimkar 670b07682b6SSantosh Shilimkar if (consumers) { 671b07682b6SSantosh Shilimkar pdata->consumer_supplies = consumers; 672b07682b6SSantosh Shilimkar pdata->num_consumer_supplies = num_consumers; 673b07682b6SSantosh Shilimkar } 674b07682b6SSantosh Shilimkar 67563bfff4eSTero Kristo if (pdata->driver_data) { 67663bfff4eSTero Kristo /* If we have existing drv_data, just add the flags */ 67763bfff4eSTero Kristo struct twl_regulator_driver_data *tmp; 67863bfff4eSTero Kristo tmp = pdata->driver_data; 67963bfff4eSTero Kristo tmp->features |= features; 68063bfff4eSTero Kristo } else { 68163bfff4eSTero Kristo /* add new driver data struct, used only during init */ 68263bfff4eSTero Kristo drv_data.features = features; 68363bfff4eSTero Kristo drv_data.set_voltage = NULL; 68463bfff4eSTero Kristo drv_data.get_voltage = NULL; 68563bfff4eSTero Kristo drv_data.data = NULL; 68663bfff4eSTero Kristo pdata->driver_data = &drv_data; 68763bfff4eSTero Kristo } 688521d8ec3SGraeme Gregory 689b07682b6SSantosh Shilimkar /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ 6903c330279SPeter Ujfalusi return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num, 691b07682b6SSantosh Shilimkar pdata, sizeof(*pdata), false, 0, 0); 692b07682b6SSantosh Shilimkar } 693b07682b6SSantosh Shilimkar 694b07682b6SSantosh Shilimkar static struct device * 695521d8ec3SGraeme Gregory add_regulator(int num, struct regulator_init_data *pdata, 696521d8ec3SGraeme Gregory unsigned long features) 697b07682b6SSantosh Shilimkar { 698521d8ec3SGraeme Gregory return add_regulator_linked(num, pdata, NULL, 0, features); 699b07682b6SSantosh Shilimkar } 700b07682b6SSantosh Shilimkar 701b07682b6SSantosh Shilimkar /* 702b07682b6SSantosh Shilimkar * NOTE: We know the first 8 IRQs after pdata->base_irq are 703b07682b6SSantosh Shilimkar * for the PIH, and the next are for the PWR_INT SIH, since 704b07682b6SSantosh Shilimkar * that's how twl_init_irq() sets things up. 705b07682b6SSantosh Shilimkar */ 706b07682b6SSantosh Shilimkar 707b07682b6SSantosh Shilimkar static int 7089e178620SFelipe Balbi add_children(struct twl4030_platform_data *pdata, unsigned irq_base, 7099e178620SFelipe Balbi unsigned long features) 710b07682b6SSantosh Shilimkar { 711b07682b6SSantosh Shilimkar struct device *child; 712b07682b6SSantosh Shilimkar 713f78959cfSThierry Reding if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { 7143c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio", 715b07682b6SSantosh Shilimkar pdata->gpio, sizeof(*pdata->gpio), 7169e178620SFelipe Balbi false, irq_base + GPIO_INTR_OFFSET, 0); 717b07682b6SSantosh Shilimkar if (IS_ERR(child)) 718b07682b6SSantosh Shilimkar return PTR_ERR(child); 719b07682b6SSantosh Shilimkar } 720b07682b6SSantosh Shilimkar 721f78959cfSThierry Reding if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { 7223c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad", 723b07682b6SSantosh Shilimkar pdata->keypad, sizeof(*pdata->keypad), 7249e178620SFelipe Balbi true, irq_base + KEYPAD_INTR_OFFSET, 0); 725b07682b6SSantosh Shilimkar if (IS_ERR(child)) 726b07682b6SSantosh Shilimkar return PTR_ERR(child); 727b07682b6SSantosh Shilimkar } 728b07682b6SSantosh Shilimkar 72924ae36f5SPeter Ujfalusi if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc && 73024ae36f5SPeter Ujfalusi twl_class_is_4030()) { 7313c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_MADC, "twl4030_madc", 732b07682b6SSantosh Shilimkar pdata->madc, sizeof(*pdata->madc), 7339e178620SFelipe Balbi true, irq_base + MADC_INTR_OFFSET, 0); 734b07682b6SSantosh Shilimkar if (IS_ERR(child)) 735b07682b6SSantosh Shilimkar return PTR_ERR(child); 736b07682b6SSantosh Shilimkar } 737b07682b6SSantosh Shilimkar 738f78959cfSThierry Reding if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { 739b07682b6SSantosh Shilimkar /* 740b07682b6SSantosh Shilimkar * REVISIT platform_data here currently might expose the 741b07682b6SSantosh Shilimkar * "msecure" line ... but for now we just expect board 742b07682b6SSantosh Shilimkar * setup to tell the chip "it's always ok to SET_TIME". 743b07682b6SSantosh Shilimkar * Eventually, Linux might become more aware of such 744b07682b6SSantosh Shilimkar * HW security concerns, and "least privilege". 745b07682b6SSantosh Shilimkar */ 7463c330279SPeter Ujfalusi child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0, 7479e178620SFelipe Balbi true, irq_base + RTC_INTR_OFFSET, 0); 748b07682b6SSantosh Shilimkar if (IS_ERR(child)) 749b07682b6SSantosh Shilimkar return PTR_ERR(child); 750b07682b6SSantosh Shilimkar } 751b07682b6SSantosh Shilimkar 752afc45898SPeter Ujfalusi if (IS_ENABLED(CONFIG_PWM_TWL)) { 7533c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0, 754afc45898SPeter Ujfalusi false, 0, 0); 755afc45898SPeter Ujfalusi if (IS_ERR(child)) 756afc45898SPeter Ujfalusi return PTR_ERR(child); 757afc45898SPeter Ujfalusi } 758afc45898SPeter Ujfalusi 759afc45898SPeter Ujfalusi if (IS_ENABLED(CONFIG_PWM_TWL_LED)) { 7603c330279SPeter Ujfalusi child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0, 76148a364b7SThierry Reding false, 0, 0); 76248a364b7SThierry Reding if (IS_ERR(child)) 76348a364b7SThierry Reding return PTR_ERR(child); 76448a364b7SThierry Reding } 76548a364b7SThierry Reding 766f78959cfSThierry Reding if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && 767f78959cfSThierry Reding twl_class_is_4030()) { 768b07682b6SSantosh Shilimkar 769b07682b6SSantosh Shilimkar static struct regulator_consumer_supply usb1v5 = { 770b07682b6SSantosh Shilimkar .supply = "usb1v5", 771b07682b6SSantosh Shilimkar }; 772b07682b6SSantosh Shilimkar static struct regulator_consumer_supply usb1v8 = { 773b07682b6SSantosh Shilimkar .supply = "usb1v8", 774b07682b6SSantosh Shilimkar }; 775e57c4a67SNeilBrown static struct regulator_consumer_supply usb3v1 = { 776e57c4a67SNeilBrown .supply = "usb3v1", 777b07682b6SSantosh Shilimkar }; 778b07682b6SSantosh Shilimkar 779b07682b6SSantosh Shilimkar /* First add the regulators so that they can be used by transceiver */ 780f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { 781b07682b6SSantosh Shilimkar /* this is a template that gets copied */ 782b07682b6SSantosh Shilimkar struct regulator_init_data usb_fixed = { 783b07682b6SSantosh Shilimkar .constraints.valid_modes_mask = 784b07682b6SSantosh Shilimkar REGULATOR_MODE_NORMAL 785b07682b6SSantosh Shilimkar | REGULATOR_MODE_STANDBY, 786b07682b6SSantosh Shilimkar .constraints.valid_ops_mask = 787b07682b6SSantosh Shilimkar REGULATOR_CHANGE_MODE 788b07682b6SSantosh Shilimkar | REGULATOR_CHANGE_STATUS, 789b07682b6SSantosh Shilimkar }; 790b07682b6SSantosh Shilimkar 791b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB1V5, 792521d8ec3SGraeme Gregory &usb_fixed, &usb1v5, 1, 793521d8ec3SGraeme Gregory features); 794b07682b6SSantosh Shilimkar if (IS_ERR(child)) 795b07682b6SSantosh Shilimkar return PTR_ERR(child); 796b07682b6SSantosh Shilimkar 797b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB1V8, 798521d8ec3SGraeme Gregory &usb_fixed, &usb1v8, 1, 799521d8ec3SGraeme Gregory features); 800b07682b6SSantosh Shilimkar if (IS_ERR(child)) 801b07682b6SSantosh Shilimkar return PTR_ERR(child); 802b07682b6SSantosh Shilimkar 803b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB3V1, 804e57c4a67SNeilBrown &usb_fixed, &usb3v1, 1, 805521d8ec3SGraeme Gregory features); 806b07682b6SSantosh Shilimkar if (IS_ERR(child)) 807b07682b6SSantosh Shilimkar return PTR_ERR(child); 808b07682b6SSantosh Shilimkar 809b07682b6SSantosh Shilimkar } 810b07682b6SSantosh Shilimkar 8113c330279SPeter Ujfalusi child = add_child(TWL_MODULE_USB, "twl4030_usb", 8122d86ad37SPeter Ujfalusi pdata->usb, sizeof(*pdata->usb), true, 813b07682b6SSantosh Shilimkar /* irq0 = USB_PRES, irq1 = USB */ 8149e178620SFelipe Balbi irq_base + USB_PRES_INTR_OFFSET, 8159e178620SFelipe Balbi irq_base + USB_INTR_OFFSET); 816b07682b6SSantosh Shilimkar 817b07682b6SSantosh Shilimkar if (IS_ERR(child)) 818b07682b6SSantosh Shilimkar return PTR_ERR(child); 819b07682b6SSantosh Shilimkar 820b07682b6SSantosh Shilimkar /* we need to connect regulators to this transceiver */ 821f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { 8221b65fa84SMark Brown usb1v5.dev_name = dev_name(child); 8231b65fa84SMark Brown usb1v8.dev_name = dev_name(child); 824e57c4a67SNeilBrown usb3v1.dev_name = dev_name(child); 825b07682b6SSantosh Shilimkar } 826b07682b6SSantosh Shilimkar } 827b07682b6SSantosh Shilimkar 828f78959cfSThierry Reding if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { 8293c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL, 8303c330279SPeter Ujfalusi 0, false, 0, 0); 831b07682b6SSantosh Shilimkar if (IS_ERR(child)) 832b07682b6SSantosh Shilimkar return PTR_ERR(child); 833b07682b6SSantosh Shilimkar } 834b07682b6SSantosh Shilimkar 835f78959cfSThierry Reding if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { 8363c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton", 8373c330279SPeter Ujfalusi NULL, 0, true, irq_base + 8 + 0, 0); 838b07682b6SSantosh Shilimkar if (IS_ERR(child)) 839b07682b6SSantosh Shilimkar return PTR_ERR(child); 840b07682b6SSantosh Shilimkar } 841b07682b6SSantosh Shilimkar 842f78959cfSThierry Reding if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && 843f78959cfSThierry Reding twl_class_is_4030()) { 8443c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio", 8454ae6df5eSPeter Ujfalusi pdata->audio, sizeof(*pdata->audio), 846d62abe56SMisael Lopez Cruz false, 0, 0); 847d62abe56SMisael Lopez Cruz if (IS_ERR(child)) 848d62abe56SMisael Lopez Cruz return PTR_ERR(child); 849d62abe56SMisael Lopez Cruz } 850d62abe56SMisael Lopez Cruz 8519da66539SRajendra Nayak /* twl4030 regulators */ 852f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { 853521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, 854521d8ec3SGraeme Gregory features); 855b07682b6SSantosh Shilimkar if (IS_ERR(child)) 856b07682b6SSantosh Shilimkar return PTR_ERR(child); 857b07682b6SSantosh Shilimkar 858521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VIO, pdata->vio, 859521d8ec3SGraeme Gregory features); 860b07682b6SSantosh Shilimkar if (IS_ERR(child)) 861b07682b6SSantosh Shilimkar return PTR_ERR(child); 862b07682b6SSantosh Shilimkar 863521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1, 864521d8ec3SGraeme Gregory features); 865b07682b6SSantosh Shilimkar if (IS_ERR(child)) 866b07682b6SSantosh Shilimkar return PTR_ERR(child); 867b07682b6SSantosh Shilimkar 868521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2, 869521d8ec3SGraeme Gregory features); 870b07682b6SSantosh Shilimkar if (IS_ERR(child)) 871b07682b6SSantosh Shilimkar return PTR_ERR(child); 872b07682b6SSantosh Shilimkar 873521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1, 874521d8ec3SGraeme Gregory features); 875b07682b6SSantosh Shilimkar if (IS_ERR(child)) 876b07682b6SSantosh Shilimkar return PTR_ERR(child); 877b07682b6SSantosh Shilimkar 878521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDAC, pdata->vdac, 879521d8ec3SGraeme Gregory features); 880b07682b6SSantosh Shilimkar if (IS_ERR(child)) 881b07682b6SSantosh Shilimkar return PTR_ERR(child); 882b07682b6SSantosh Shilimkar 883b07682b6SSantosh Shilimkar child = add_regulator((features & TWL4030_VAUX2) 884b07682b6SSantosh Shilimkar ? TWL4030_REG_VAUX2_4030 885b07682b6SSantosh Shilimkar : TWL4030_REG_VAUX2, 886521d8ec3SGraeme Gregory pdata->vaux2, features); 887b07682b6SSantosh Shilimkar if (IS_ERR(child)) 888b07682b6SSantosh Shilimkar return PTR_ERR(child); 889b07682b6SSantosh Shilimkar 890521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1, 891521d8ec3SGraeme Gregory features); 892b07682b6SSantosh Shilimkar if (IS_ERR(child)) 893b07682b6SSantosh Shilimkar return PTR_ERR(child); 894b07682b6SSantosh Shilimkar 895521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2, 896521d8ec3SGraeme Gregory features); 897b07682b6SSantosh Shilimkar if (IS_ERR(child)) 898b07682b6SSantosh Shilimkar return PTR_ERR(child); 899b07682b6SSantosh Shilimkar 900521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig, 901521d8ec3SGraeme Gregory features); 902b07682b6SSantosh Shilimkar if (IS_ERR(child)) 903b07682b6SSantosh Shilimkar return PTR_ERR(child); 904b07682b6SSantosh Shilimkar } 905b07682b6SSantosh Shilimkar 906b07682b6SSantosh Shilimkar /* maybe add LDOs that are omitted on cost-reduced parts */ 907f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) 9089da66539SRajendra Nayak && twl_class_is_4030()) { 909521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, 910521d8ec3SGraeme Gregory features); 911b07682b6SSantosh Shilimkar if (IS_ERR(child)) 912b07682b6SSantosh Shilimkar return PTR_ERR(child); 913b07682b6SSantosh Shilimkar 914521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2, 915521d8ec3SGraeme Gregory features); 916b07682b6SSantosh Shilimkar if (IS_ERR(child)) 917b07682b6SSantosh Shilimkar return PTR_ERR(child); 918b07682b6SSantosh Shilimkar 919521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VSIM, pdata->vsim, 920521d8ec3SGraeme Gregory features); 921b07682b6SSantosh Shilimkar if (IS_ERR(child)) 922b07682b6SSantosh Shilimkar return PTR_ERR(child); 923b07682b6SSantosh Shilimkar 924521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1, 925521d8ec3SGraeme Gregory features); 926b07682b6SSantosh Shilimkar if (IS_ERR(child)) 927b07682b6SSantosh Shilimkar return PTR_ERR(child); 928b07682b6SSantosh Shilimkar 929521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3, 930521d8ec3SGraeme Gregory features); 931b07682b6SSantosh Shilimkar if (IS_ERR(child)) 932b07682b6SSantosh Shilimkar return PTR_ERR(child); 933b07682b6SSantosh Shilimkar 934521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4, 935521d8ec3SGraeme Gregory features); 936b07682b6SSantosh Shilimkar if (IS_ERR(child)) 937b07682b6SSantosh Shilimkar return PTR_ERR(child); 938b07682b6SSantosh Shilimkar } 939b07682b6SSantosh Shilimkar 940f78959cfSThierry Reding if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && 94111c39c4bSGrazvydas Ignotas !(features & (TPS_SUBSET | TWL5031))) { 9423c330279SPeter Ujfalusi child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci", 94311c39c4bSGrazvydas Ignotas pdata->bci, sizeof(*pdata->bci), false, 94411c39c4bSGrazvydas Ignotas /* irq0 = CHG_PRES, irq1 = BCI */ 9459e178620SFelipe Balbi irq_base + BCI_PRES_INTR_OFFSET, 9469e178620SFelipe Balbi irq_base + BCI_INTR_OFFSET); 94711c39c4bSGrazvydas Ignotas if (IS_ERR(child)) 94811c39c4bSGrazvydas Ignotas return PTR_ERR(child); 94911c39c4bSGrazvydas Ignotas } 95011c39c4bSGrazvydas Ignotas 951637d6895SFlorian Vaussard if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) { 952637d6895SFlorian Vaussard child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power", 953637d6895SFlorian Vaussard pdata->power, sizeof(*pdata->power), false, 954637d6895SFlorian Vaussard 0, 0); 955637d6895SFlorian Vaussard if (IS_ERR(child)) 956637d6895SFlorian Vaussard return PTR_ERR(child); 957637d6895SFlorian Vaussard } 958637d6895SFlorian Vaussard 959b07682b6SSantosh Shilimkar return 0; 960b07682b6SSantosh Shilimkar } 961b07682b6SSantosh Shilimkar 962b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 963b07682b6SSantosh Shilimkar 964b07682b6SSantosh Shilimkar /* 965b07682b6SSantosh Shilimkar * These three functions initialize the on-chip clock framework, 966b07682b6SSantosh Shilimkar * letting it generate the right frequencies for USB, MADC, and 967b07682b6SSantosh Shilimkar * other purposes. 968b07682b6SSantosh Shilimkar */ 96988385550SNathan Chancellor static inline int protect_pm_master(void) 970b07682b6SSantosh Shilimkar { 971b07682b6SSantosh Shilimkar int e = 0; 972b07682b6SSantosh Shilimkar 973d640e757SPeter Ujfalusi e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, 97449e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 975b07682b6SSantosh Shilimkar return e; 976b07682b6SSantosh Shilimkar } 977b07682b6SSantosh Shilimkar 97888385550SNathan Chancellor static inline int unprotect_pm_master(void) 979b07682b6SSantosh Shilimkar { 980b07682b6SSantosh Shilimkar int e = 0; 981b07682b6SSantosh Shilimkar 982d640e757SPeter Ujfalusi e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, 98349e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 984d640e757SPeter Ujfalusi e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, 98549e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 98649e6f87eSFelipe Balbi 987b07682b6SSantosh Shilimkar return e; 988b07682b6SSantosh Shilimkar } 989b07682b6SSantosh Shilimkar 990b07682b6SSantosh Shilimkar static void clocks_init(struct device *dev, 991b07682b6SSantosh Shilimkar struct twl4030_clock_init_data *clock) 992b07682b6SSantosh Shilimkar { 993b07682b6SSantosh Shilimkar int e = 0; 994b07682b6SSantosh Shilimkar struct clk *osc; 995b07682b6SSantosh Shilimkar u32 rate; 996b07682b6SSantosh Shilimkar u8 ctrl = HFCLK_FREQ_26_MHZ; 997b07682b6SSantosh Shilimkar 998defa6be1STony Lindgren osc = clk_get(dev, "fck"); 999b07682b6SSantosh Shilimkar if (IS_ERR(osc)) { 1000fc7b92fcSBalaji T K printk(KERN_WARNING "Skipping twl internal clock init and " 1001b07682b6SSantosh Shilimkar "using bootloader value (unknown osc rate)\n"); 1002b07682b6SSantosh Shilimkar return; 1003b07682b6SSantosh Shilimkar } 1004b07682b6SSantosh Shilimkar 1005b07682b6SSantosh Shilimkar rate = clk_get_rate(osc); 1006b07682b6SSantosh Shilimkar clk_put(osc); 1007b07682b6SSantosh Shilimkar 1008b07682b6SSantosh Shilimkar switch (rate) { 1009b07682b6SSantosh Shilimkar case 19200000: 1010b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_19p2_MHZ; 1011b07682b6SSantosh Shilimkar break; 1012b07682b6SSantosh Shilimkar case 26000000: 1013b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_26_MHZ; 1014b07682b6SSantosh Shilimkar break; 1015b07682b6SSantosh Shilimkar case 38400000: 1016b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_38p4_MHZ; 1017b07682b6SSantosh Shilimkar break; 1018b07682b6SSantosh Shilimkar } 1019b07682b6SSantosh Shilimkar 1020b07682b6SSantosh Shilimkar ctrl |= HIGH_PERF_SQ; 1021b07682b6SSantosh Shilimkar if (clock && clock->ck32k_lowpwr_enable) 1022b07682b6SSantosh Shilimkar ctrl |= CK32K_LOWPWR_EN; 1023b07682b6SSantosh Shilimkar 1024b07682b6SSantosh Shilimkar e |= unprotect_pm_master(); 1025b07682b6SSantosh Shilimkar /* effect->MADC+USB ck en */ 1026fc7b92fcSBalaji T K e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); 1027b07682b6SSantosh Shilimkar e |= protect_pm_master(); 1028b07682b6SSantosh Shilimkar 1029b07682b6SSantosh Shilimkar if (e < 0) 1030b07682b6SSantosh Shilimkar pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e); 1031b07682b6SSantosh Shilimkar } 1032b07682b6SSantosh Shilimkar 1033b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 1034b07682b6SSantosh Shilimkar 1035b07682b6SSantosh Shilimkar 1036fc7b92fcSBalaji T K static int twl_remove(struct i2c_client *client) 1037b07682b6SSantosh Shilimkar { 1038364cedb2SPeter Ujfalusi unsigned i, num_slaves; 1039b07682b6SSantosh Shilimkar 10406dd810b5SPeter Ujfalusi if (twl_class_is_4030()) 1041*724c3be3SUwe Kleine-König twl4030_exit_irq(); 10426dd810b5SPeter Ujfalusi else 1043b6f29431SUwe Kleine-König twl6030_exit_irq(); 1044e8deb28cSBalaji T K 10456dd810b5SPeter Ujfalusi num_slaves = twl_get_num_slaves(); 1046364cedb2SPeter Ujfalusi for (i = 0; i < num_slaves; i++) { 104780a97ccdSPeter Ujfalusi struct twl_client *twl = &twl_priv->twl_modules[i]; 1048b07682b6SSantosh Shilimkar 1049b07682b6SSantosh Shilimkar if (twl->client && twl->client != client) 1050b07682b6SSantosh Shilimkar i2c_unregister_device(twl->client); 105180a97ccdSPeter Ujfalusi twl->client = NULL; 1052b07682b6SSantosh Shilimkar } 105380a97ccdSPeter Ujfalusi twl_priv->ready = false; 1054b07682b6SSantosh Shilimkar return 0; 1055b07682b6SSantosh Shilimkar } 1056b07682b6SSantosh Shilimkar 105780ec831eSTony Lindgren static struct of_dev_auxdata twl_auxdata_lookup[] = { 105880ec831eSTony Lindgren OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), 105980ec831eSTony Lindgren { /* sentinel */ }, 106080ec831eSTony Lindgren }; 106180ec831eSTony Lindgren 1062ec1a07b3SBenoit Cousson /* NOTE: This driver only handles a single twl4030/tps659x0 chip */ 1063f791be49SBill Pemberton static int 1064fc7b92fcSBalaji T K twl_probe(struct i2c_client *client, const struct i2c_device_id *id) 1065b07682b6SSantosh Shilimkar { 1066334a41ceSJingoo Han struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev); 1067aeb5032bSBenoit Cousson struct device_node *node = client->dev.of_node; 1068defa6be1STony Lindgren struct platform_device *pdev; 1069d842b61bSKrzysztof Kozlowski const struct regmap_config *twl_regmap_config; 1070ec1a07b3SBenoit Cousson int irq_base = 0; 1071ec1a07b3SBenoit Cousson int status; 1072364cedb2SPeter Ujfalusi unsigned i, num_slaves; 1073aeb5032bSBenoit Cousson 10747e2e6c57SPeter Ujfalusi if (!node && !pdata) { 10757e2e6c57SPeter Ujfalusi dev_err(&client->dev, "no platform data\n"); 10767e2e6c57SPeter Ujfalusi return -EINVAL; 10777e2e6c57SPeter Ujfalusi } 10787e2e6c57SPeter Ujfalusi 107980a97ccdSPeter Ujfalusi if (twl_priv) { 10806382a061SPeter Ujfalusi dev_dbg(&client->dev, "only one instance of %s allowed\n", 10816382a061SPeter Ujfalusi DRIVER_NAME); 10826382a061SPeter Ujfalusi return -EBUSY; 10836382a061SPeter Ujfalusi } 10846382a061SPeter Ujfalusi 1085defa6be1STony Lindgren pdev = platform_device_alloc(DRIVER_NAME, -1); 1086defa6be1STony Lindgren if (!pdev) { 1087defa6be1STony Lindgren dev_err(&client->dev, "can't alloc pdev\n"); 1088defa6be1STony Lindgren return -ENOMEM; 1089defa6be1STony Lindgren } 1090defa6be1STony Lindgren 1091defa6be1STony Lindgren status = platform_device_add(pdev); 1092defa6be1STony Lindgren if (status) { 1093defa6be1STony Lindgren platform_device_put(pdev); 1094defa6be1STony Lindgren return status; 1095defa6be1STony Lindgren } 1096defa6be1STony Lindgren 1097b07682b6SSantosh Shilimkar if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { 1098b07682b6SSantosh Shilimkar dev_dbg(&client->dev, "can't talk I2C?\n"); 1099defa6be1STony Lindgren status = -EIO; 1100defa6be1STony Lindgren goto free; 1101b07682b6SSantosh Shilimkar } 1102b07682b6SSantosh Shilimkar 110380a97ccdSPeter Ujfalusi twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private), 110480a97ccdSPeter Ujfalusi GFP_KERNEL); 110580a97ccdSPeter Ujfalusi if (!twl_priv) { 110680a97ccdSPeter Ujfalusi status = -ENOMEM; 110780a97ccdSPeter Ujfalusi goto free; 110880a97ccdSPeter Ujfalusi } 110980a97ccdSPeter Ujfalusi 1110364cedb2SPeter Ujfalusi if ((id->driver_data) & TWL6030_CLASS) { 111180a97ccdSPeter Ujfalusi twl_priv->twl_id = TWL6030_CLASS_ID; 111280a97ccdSPeter Ujfalusi twl_priv->twl_map = &twl6030_map[0]; 111389ce43fbSGraeme Gregory /* The charger base address is different in twl6032 */ 111489ce43fbSGraeme Gregory if ((id->driver_data) & TWL6032_SUBCLASS) 111580a97ccdSPeter Ujfalusi twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base = 111689ce43fbSGraeme Gregory TWL6032_BASEADD_CHARGER; 11172473d25aSPeter Ujfalusi twl_regmap_config = twl6030_regmap_config; 1118364cedb2SPeter Ujfalusi } else { 111980a97ccdSPeter Ujfalusi twl_priv->twl_id = TWL4030_CLASS_ID; 112080a97ccdSPeter Ujfalusi twl_priv->twl_map = &twl4030_map[0]; 11212473d25aSPeter Ujfalusi twl_regmap_config = twl4030_regmap_config; 11226dd810b5SPeter Ujfalusi } 11236dd810b5SPeter Ujfalusi 11246dd810b5SPeter Ujfalusi num_slaves = twl_get_num_slaves(); 1125a86854d0SKees Cook twl_priv->twl_modules = devm_kcalloc(&client->dev, 1126a86854d0SKees Cook num_slaves, 1127a86854d0SKees Cook sizeof(struct twl_client), 11286dd810b5SPeter Ujfalusi GFP_KERNEL); 112980a97ccdSPeter Ujfalusi if (!twl_priv->twl_modules) { 11306dd810b5SPeter Ujfalusi status = -ENOMEM; 11316dd810b5SPeter Ujfalusi goto free; 1132364cedb2SPeter Ujfalusi } 1133364cedb2SPeter Ujfalusi 1134364cedb2SPeter Ujfalusi for (i = 0; i < num_slaves; i++) { 113580a97ccdSPeter Ujfalusi struct twl_client *twl = &twl_priv->twl_modules[i]; 1136b07682b6SSantosh Shilimkar 1137ec1a07b3SBenoit Cousson if (i == 0) { 1138b07682b6SSantosh Shilimkar twl->client = client; 1139ec1a07b3SBenoit Cousson } else { 1140ba972dacSWolfram Sang twl->client = i2c_new_dummy_device(client->adapter, 11412473d25aSPeter Ujfalusi client->addr + i); 1142ba972dacSWolfram Sang if (IS_ERR(twl->client)) { 1143b07682b6SSantosh Shilimkar dev_err(&client->dev, 1144b07682b6SSantosh Shilimkar "can't attach client %d\n", i); 1145ba972dacSWolfram Sang status = PTR_ERR(twl->client); 1146b07682b6SSantosh Shilimkar goto fail; 1147b07682b6SSantosh Shilimkar } 1148b07682b6SSantosh Shilimkar } 11492473d25aSPeter Ujfalusi 11502473d25aSPeter Ujfalusi twl->regmap = devm_regmap_init_i2c(twl->client, 11512473d25aSPeter Ujfalusi &twl_regmap_config[i]); 11522473d25aSPeter Ujfalusi if (IS_ERR(twl->regmap)) { 11532473d25aSPeter Ujfalusi status = PTR_ERR(twl->regmap); 11542473d25aSPeter Ujfalusi dev_err(&client->dev, 11552473d25aSPeter Ujfalusi "Failed to allocate regmap %d, err: %d\n", i, 11562473d25aSPeter Ujfalusi status); 11572473d25aSPeter Ujfalusi goto fail; 11582473d25aSPeter Ujfalusi } 1159b07682b6SSantosh Shilimkar } 1160ec1a07b3SBenoit Cousson 116180a97ccdSPeter Ujfalusi twl_priv->ready = true; 1162b07682b6SSantosh Shilimkar 1163b07682b6SSantosh Shilimkar /* setup clock framework */ 1164c218b3b2SPeter Ujfalusi clocks_init(&client->dev, pdata ? pdata->clock : NULL); 1165b07682b6SSantosh Shilimkar 1166ca972d13SLesly A M /* read TWL IDCODE Register */ 116780a97ccdSPeter Ujfalusi if (twl_class_is_4030()) { 1168ec1a07b3SBenoit Cousson status = twl_read_idcode_register(); 1169ec1a07b3SBenoit Cousson WARN(status < 0, "Error: reading twl_idcode register value\n"); 1170ca972d13SLesly A M } 1171ca972d13SLesly A M 1172b07682b6SSantosh Shilimkar /* Maybe init the T2 Interrupt subsystem */ 11739e178620SFelipe Balbi if (client->irq) { 1174e8deb28cSBalaji T K if (twl_class_is_4030()) { 1175e8deb28cSBalaji T K twl4030_init_chip_irq(id->name); 117678518ffaSBenoit Cousson irq_base = twl4030_init_irq(&client->dev, client->irq); 1177e8deb28cSBalaji T K } else { 117878518ffaSBenoit Cousson irq_base = twl6030_init_irq(&client->dev, client->irq); 1179e8deb28cSBalaji T K } 1180e8deb28cSBalaji T K 118178518ffaSBenoit Cousson if (irq_base < 0) { 118278518ffaSBenoit Cousson status = irq_base; 1183b07682b6SSantosh Shilimkar goto fail; 1184b07682b6SSantosh Shilimkar } 118578518ffaSBenoit Cousson } 1186b07682b6SSantosh Shilimkar 1187ec1a07b3SBenoit Cousson /* 1188ec1a07b3SBenoit Cousson * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. 1189a29aaf55SMoiz Sonasath * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, 1190a29aaf55SMoiz Sonasath * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. 1191a613b739STony Lindgren * 1192a613b739STony Lindgren * Also, always enable SmartReflex bit as that's needed for omaps to 1193a613b739STony Lindgren * to do anything over I2C4 for voltage scaling even if SmartReflex 1194a613b739STony Lindgren * is disabled. Without the SmartReflex bit omap sys_clkreq idle 1195a613b739STony Lindgren * signal will never trigger for retention idle. 1196a29aaf55SMoiz Sonasath */ 1197a29aaf55SMoiz Sonasath if (twl_class_is_4030()) { 1198ec1a07b3SBenoit Cousson u8 temp; 1199ec1a07b3SBenoit Cousson 1200a29aaf55SMoiz Sonasath twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1); 1201a29aaf55SMoiz Sonasath temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ 1202a29aaf55SMoiz Sonasath I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); 1203a29aaf55SMoiz Sonasath twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); 1204a613b739STony Lindgren 1205a613b739STony Lindgren twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, 1206a613b739STony Lindgren TWL4030_DCDC_GLOBAL_CFG); 1207a613b739STony Lindgren temp |= SMARTREFLEX_ENABLE; 1208a613b739STony Lindgren twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, 1209a613b739STony Lindgren TWL4030_DCDC_GLOBAL_CFG); 1210a29aaf55SMoiz Sonasath } 1211a29aaf55SMoiz Sonasath 121280ec831eSTony Lindgren if (node) { 121380ec831eSTony Lindgren if (pdata) 121480ec831eSTony Lindgren twl_auxdata_lookup[0].platform_data = pdata->gpio; 121580ec831eSTony Lindgren status = of_platform_populate(node, NULL, twl_auxdata_lookup, 121680ec831eSTony Lindgren &client->dev); 121780ec831eSTony Lindgren } else { 12189e178620SFelipe Balbi status = add_children(pdata, irq_base, id->driver_data); 121980ec831eSTony Lindgren } 1220aeb5032bSBenoit Cousson 1221b07682b6SSantosh Shilimkar fail: 1222b07682b6SSantosh Shilimkar if (status < 0) 1223fc7b92fcSBalaji T K twl_remove(client); 1224defa6be1STony Lindgren free: 1225defa6be1STony Lindgren if (status < 0) 1226defa6be1STony Lindgren platform_device_unregister(pdev); 1227ec1a07b3SBenoit Cousson 1228b07682b6SSantosh Shilimkar return status; 1229b07682b6SSantosh Shilimkar } 1230b07682b6SSantosh Shilimkar 123120bb907fSAndreas Kemnade static int __maybe_unused twl_suspend(struct device *dev) 123220bb907fSAndreas Kemnade { 123320bb907fSAndreas Kemnade struct i2c_client *client = to_i2c_client(dev); 123420bb907fSAndreas Kemnade 123520bb907fSAndreas Kemnade if (client->irq) 123620bb907fSAndreas Kemnade disable_irq(client->irq); 123720bb907fSAndreas Kemnade 123820bb907fSAndreas Kemnade return 0; 123920bb907fSAndreas Kemnade } 124020bb907fSAndreas Kemnade 124120bb907fSAndreas Kemnade static int __maybe_unused twl_resume(struct device *dev) 124220bb907fSAndreas Kemnade { 124320bb907fSAndreas Kemnade struct i2c_client *client = to_i2c_client(dev); 124420bb907fSAndreas Kemnade 124520bb907fSAndreas Kemnade if (client->irq) 124620bb907fSAndreas Kemnade enable_irq(client->irq); 124720bb907fSAndreas Kemnade 124820bb907fSAndreas Kemnade return 0; 124920bb907fSAndreas Kemnade } 125020bb907fSAndreas Kemnade 125120bb907fSAndreas Kemnade static SIMPLE_DEV_PM_OPS(twl_dev_pm_ops, twl_suspend, twl_resume); 125220bb907fSAndreas Kemnade 1253fc7b92fcSBalaji T K static const struct i2c_device_id twl_ids[] = { 1254b07682b6SSantosh Shilimkar { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ 1255b07682b6SSantosh Shilimkar { "twl5030", 0 }, /* T2 updated */ 1256b07682b6SSantosh Shilimkar { "twl5031", TWL5031 }, /* TWL5030 updated */ 1257b07682b6SSantosh Shilimkar { "tps65950", 0 }, /* catalog version of twl5030 */ 1258b07682b6SSantosh Shilimkar { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ 1259b07682b6SSantosh Shilimkar { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ 126059dead5aSOleg Drokin { "tps65921", TPS_SUBSET }, /* fewer LDOs; no codec, no LED 126159dead5aSOleg Drokin and vibrator. Charger in USB module*/ 1262e8deb28cSBalaji T K { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ 126389ce43fbSGraeme Gregory { "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */ 1264b07682b6SSantosh Shilimkar { /* end of list */ }, 1265b07682b6SSantosh Shilimkar }; 1266b07682b6SSantosh Shilimkar 1267b07682b6SSantosh Shilimkar /* One Client Driver , 4 Clients */ 1268fc7b92fcSBalaji T K static struct i2c_driver twl_driver = { 1269b07682b6SSantosh Shilimkar .driver.name = DRIVER_NAME, 127020bb907fSAndreas Kemnade .driver.pm = &twl_dev_pm_ops, 1271fc7b92fcSBalaji T K .id_table = twl_ids, 1272fc7b92fcSBalaji T K .probe = twl_probe, 1273fc7b92fcSBalaji T K .remove = twl_remove, 1274b07682b6SSantosh Shilimkar }; 12757a243b63SPaul Gortmaker builtin_i2c_driver(twl_driver); 1276