1b07682b6SSantosh Shilimkar /* 2fc7b92fcSBalaji T K * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM 3fc7b92fcSBalaji T K * and audio CODEC devices 4b07682b6SSantosh Shilimkar * 5b07682b6SSantosh Shilimkar * Copyright (C) 2005-2006 Texas Instruments, Inc. 6b07682b6SSantosh Shilimkar * 7b07682b6SSantosh Shilimkar * Modifications to defer interrupt handling to a kernel thread: 8b07682b6SSantosh Shilimkar * Copyright (C) 2006 MontaVista Software, Inc. 9b07682b6SSantosh Shilimkar * 10b07682b6SSantosh Shilimkar * Based on tlv320aic23.c: 11b07682b6SSantosh Shilimkar * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> 12b07682b6SSantosh Shilimkar * 13b07682b6SSantosh Shilimkar * Code cleanup and modifications to IRQ handler. 14b07682b6SSantosh Shilimkar * by syed khasim <x0khasim@ti.com> 15b07682b6SSantosh Shilimkar * 16b07682b6SSantosh Shilimkar * This program is free software; you can redistribute it and/or modify 17b07682b6SSantosh Shilimkar * it under the terms of the GNU General Public License as published by 18b07682b6SSantosh Shilimkar * the Free Software Foundation; either version 2 of the License, or 19b07682b6SSantosh Shilimkar * (at your option) any later version. 20b07682b6SSantosh Shilimkar * 21b07682b6SSantosh Shilimkar * This program is distributed in the hope that it will be useful, 22b07682b6SSantosh Shilimkar * but WITHOUT ANY WARRANTY; without even the implied warranty of 23b07682b6SSantosh Shilimkar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24b07682b6SSantosh Shilimkar * GNU General Public License for more details. 25b07682b6SSantosh Shilimkar * 26b07682b6SSantosh Shilimkar * You should have received a copy of the GNU General Public License 27b07682b6SSantosh Shilimkar * along with this program; if not, write to the Free Software 28b07682b6SSantosh Shilimkar * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29b07682b6SSantosh Shilimkar */ 30b07682b6SSantosh Shilimkar 31b07682b6SSantosh Shilimkar #include <linux/init.h> 32b07682b6SSantosh Shilimkar #include <linux/mutex.h> 334e36dd33SPaul Gortmaker #include <linux/module.h> 34b07682b6SSantosh Shilimkar #include <linux/platform_device.h> 352473d25aSPeter Ujfalusi #include <linux/regmap.h> 36b07682b6SSantosh Shilimkar #include <linux/clk.h> 37b07682b6SSantosh Shilimkar #include <linux/err.h> 38aeb5032bSBenoit Cousson #include <linux/device.h> 39aeb5032bSBenoit Cousson #include <linux/of.h> 40aeb5032bSBenoit Cousson #include <linux/of_irq.h> 41aeb5032bSBenoit Cousson #include <linux/of_platform.h> 42e7cc3acaSGrant Likely #include <linux/irq.h> 43aeb5032bSBenoit Cousson #include <linux/irqdomain.h> 44b07682b6SSantosh Shilimkar 45b07682b6SSantosh Shilimkar #include <linux/regulator/machine.h> 46b07682b6SSantosh Shilimkar 47b07682b6SSantosh Shilimkar #include <linux/i2c.h> 48b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h> 49b07682b6SSantosh Shilimkar 5091460700SPeter Ujfalusi /* Register descriptions for audio */ 5191460700SPeter Ujfalusi #include <linux/mfd/twl4030-audio.h> 5291460700SPeter Ujfalusi 531b8f333fSBenoit Cousson #include "twl-core.h" 54b07682b6SSantosh Shilimkar 55b07682b6SSantosh Shilimkar /* 56b07682b6SSantosh Shilimkar * The TWL4030 "Triton 2" is one of a family of a multi-function "Power 57b07682b6SSantosh Shilimkar * Management and System Companion Device" chips originally designed for 58b07682b6SSantosh Shilimkar * use in OMAP2 and OMAP 3 based systems. Its control interfaces use I2C, 59b07682b6SSantosh Shilimkar * often at around 3 Mbit/sec, including for interrupt handling. 60b07682b6SSantosh Shilimkar * 61b07682b6SSantosh Shilimkar * This driver core provides genirq support for the interrupts emitted, 62b07682b6SSantosh Shilimkar * by the various modules, and exports register access primitives. 63b07682b6SSantosh Shilimkar * 64b07682b6SSantosh Shilimkar * FIXME this driver currently requires use of the first interrupt line 65b07682b6SSantosh Shilimkar * (and associated registers). 66b07682b6SSantosh Shilimkar */ 67b07682b6SSantosh Shilimkar 68fc7b92fcSBalaji T K #define DRIVER_NAME "twl" 69b07682b6SSantosh Shilimkar 70b07682b6SSantosh Shilimkar /* Triton Core internal information (BEGIN) */ 71b07682b6SSantosh Shilimkar 72b07682b6SSantosh Shilimkar /* Base Address defns for twl4030_map[] */ 73b07682b6SSantosh Shilimkar 74b07682b6SSantosh Shilimkar /* subchip/slave 0 - USB ID */ 75b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_USB 0x0000 76b07682b6SSantosh Shilimkar 77b07682b6SSantosh Shilimkar /* subchip/slave 1 - AUD ID */ 78b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_AUDIO_VOICE 0x0000 79b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_GPIO 0x0098 80b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INTBR 0x0085 81b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PIH 0x0080 82b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_TEST 0x004C 83b07682b6SSantosh Shilimkar 84b07682b6SSantosh Shilimkar /* subchip/slave 2 - AUX ID */ 85b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INTERRUPTS 0x00B9 86b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_LED 0x00EE 87b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_MADC 0x0000 88b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_MAIN_CHARGE 0x0074 89b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PRECHARGE 0x00AA 905d4e9bd7SPeter Ujfalusi #define TWL4030_BASEADD_PWM 0x00F8 91b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_KEYPAD 0x00D2 92b07682b6SSantosh Shilimkar 93b07682b6SSantosh Shilimkar #define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */ 94b07682b6SSantosh Shilimkar #define TWL5031_BASEADD_INTERRUPTS 0x00B9 /* Different than TWL4030's 95b07682b6SSantosh Shilimkar one */ 96b07682b6SSantosh Shilimkar 97b07682b6SSantosh Shilimkar /* subchip/slave 3 - POWER ID */ 98b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_BACKUP 0x0014 99b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_INT 0x002E 100b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PM_MASTER 0x0036 101a613b739STony Lindgren 102b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_PM_RECEIVER 0x005B 103a613b739STony Lindgren #define TWL4030_DCDC_GLOBAL_CFG 0x06 104a613b739STony Lindgren #define SMARTREFLEX_ENABLE BIT(3) 105a613b739STony Lindgren 106b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_RTC 0x001C 107b07682b6SSantosh Shilimkar #define TWL4030_BASEADD_SECURED_REG 0x0000 108b07682b6SSantosh Shilimkar 109b07682b6SSantosh Shilimkar /* Triton Core internal information (END) */ 110b07682b6SSantosh Shilimkar 111b07682b6SSantosh Shilimkar 112e8deb28cSBalaji T K /* subchip/slave 0 0x48 - POWER */ 113e8deb28cSBalaji T K #define TWL6030_BASEADD_RTC 0x0000 1145d4e9bd7SPeter Ujfalusi #define TWL6030_BASEADD_SECURED_REG 0x0017 115e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_MASTER 0x001F 116e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ 117e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_MISC 0x00E2 118e8deb28cSBalaji T K #define TWL6030_BASEADD_PM_PUPD 0x00F0 119e8deb28cSBalaji T K 120e8deb28cSBalaji T K /* subchip/slave 1 0x49 - FEATURE */ 121e8deb28cSBalaji T K #define TWL6030_BASEADD_USB 0x0000 122e8deb28cSBalaji T K #define TWL6030_BASEADD_GPADC_CTRL 0x002E 123e8deb28cSBalaji T K #define TWL6030_BASEADD_AUX 0x0090 124e8deb28cSBalaji T K #define TWL6030_BASEADD_PWM 0x00BA 125e8deb28cSBalaji T K #define TWL6030_BASEADD_GASGAUGE 0x00C0 126e8deb28cSBalaji T K #define TWL6030_BASEADD_PIH 0x00D0 127e8deb28cSBalaji T K #define TWL6030_BASEADD_CHARGER 0x00E0 12889ce43fbSGraeme Gregory #define TWL6032_BASEADD_CHARGER 0x00DA 1295d4e9bd7SPeter Ujfalusi #define TWL6030_BASEADD_LED 0x00F4 130e8deb28cSBalaji T K 131e8deb28cSBalaji T K /* subchip/slave 2 0x4A - DFT */ 132e8deb28cSBalaji T K #define TWL6030_BASEADD_DIEID 0x00C0 133e8deb28cSBalaji T K 134e8deb28cSBalaji T K /* subchip/slave 3 0x4B - AUDIO */ 135e8deb28cSBalaji T K #define TWL6030_BASEADD_AUDIO 0x0000 136e8deb28cSBalaji T K #define TWL6030_BASEADD_RSV 0x0000 137fa0d9762SBalaji T K #define TWL6030_BASEADD_ZERO 0x0000 138e8deb28cSBalaji T K 139b07682b6SSantosh Shilimkar /* Few power values */ 140b07682b6SSantosh Shilimkar #define R_CFG_BOOT 0x05 141b07682b6SSantosh Shilimkar 142b07682b6SSantosh Shilimkar /* some fields in R_CFG_BOOT */ 143b07682b6SSantosh Shilimkar #define HFCLK_FREQ_19p2_MHZ (1 << 0) 144b07682b6SSantosh Shilimkar #define HFCLK_FREQ_26_MHZ (2 << 0) 145b07682b6SSantosh Shilimkar #define HFCLK_FREQ_38p4_MHZ (3 << 0) 146b07682b6SSantosh Shilimkar #define HIGH_PERF_SQ (1 << 3) 147b07682b6SSantosh Shilimkar #define CK32K_LOWPWR_EN (1 << 7) 148b07682b6SSantosh Shilimkar 149b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 150b07682b6SSantosh Shilimkar 151e8deb28cSBalaji T K /* Structure for each TWL4030/TWL6030 Slave */ 152fc7b92fcSBalaji T K struct twl_client { 153b07682b6SSantosh Shilimkar struct i2c_client *client; 1542473d25aSPeter Ujfalusi struct regmap *regmap; 155b07682b6SSantosh Shilimkar }; 156b07682b6SSantosh Shilimkar 157b07682b6SSantosh Shilimkar /* mapping the module id to slave id and base address */ 158fc7b92fcSBalaji T K struct twl_mapping { 159b07682b6SSantosh Shilimkar unsigned char sid; /* Slave ID */ 160b07682b6SSantosh Shilimkar unsigned char base; /* base address */ 161b07682b6SSantosh Shilimkar }; 16280a97ccdSPeter Ujfalusi 16380a97ccdSPeter Ujfalusi struct twl_private { 16480a97ccdSPeter Ujfalusi bool ready; /* The core driver is ready to be used */ 16580a97ccdSPeter Ujfalusi u32 twl_idcode; /* TWL IDCODE Register value */ 16680a97ccdSPeter Ujfalusi unsigned int twl_id; 16780a97ccdSPeter Ujfalusi 16880a97ccdSPeter Ujfalusi struct twl_mapping *twl_map; 16980a97ccdSPeter Ujfalusi struct twl_client *twl_modules; 17080a97ccdSPeter Ujfalusi }; 17180a97ccdSPeter Ujfalusi 17280a97ccdSPeter Ujfalusi static struct twl_private *twl_priv; 173b07682b6SSantosh Shilimkar 174da059ecfSPeter Ujfalusi static struct twl_mapping twl4030_map[] = { 175b07682b6SSantosh Shilimkar /* 176b07682b6SSantosh Shilimkar * NOTE: don't change this table without updating the 177e8deb28cSBalaji T K * <linux/i2c/twl.h> defines for TWL4030_MODULE_* 178b07682b6SSantosh Shilimkar * so they continue to match the order in this table. 179b07682b6SSantosh Shilimkar */ 180b07682b6SSantosh Shilimkar 1815d4e9bd7SPeter Ujfalusi /* Common IPs */ 182b07682b6SSantosh Shilimkar { 0, TWL4030_BASEADD_USB }, 1835d4e9bd7SPeter Ujfalusi { 1, TWL4030_BASEADD_PIH }, 1845d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_MAIN_CHARGE }, 1855d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_PM_MASTER }, 1865d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_PM_RECEIVER }, 1875d4e9bd7SPeter Ujfalusi 1885d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_RTC }, 1895d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_PWM }, 1905d4e9bd7SPeter Ujfalusi { 2, TWL4030_BASEADD_LED }, 1915d4e9bd7SPeter Ujfalusi { 3, TWL4030_BASEADD_SECURED_REG }, 1925d4e9bd7SPeter Ujfalusi 1935d4e9bd7SPeter Ujfalusi /* TWL4030 specific IPs */ 194b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_AUDIO_VOICE }, 195b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_GPIO }, 196b07682b6SSantosh Shilimkar { 1, TWL4030_BASEADD_INTBR }, 1976691ccd0SPeter Ujfalusi { 1, TWL4030_BASEADD_TEST }, 198b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_KEYPAD }, 1995d4e9bd7SPeter Ujfalusi 200b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_MADC }, 201b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_INTERRUPTS }, 202b07682b6SSantosh Shilimkar { 2, TWL4030_BASEADD_PRECHARGE }, 203b07682b6SSantosh Shilimkar { 3, TWL4030_BASEADD_BACKUP }, 204b07682b6SSantosh Shilimkar { 3, TWL4030_BASEADD_INT }, 2056691ccd0SPeter Ujfalusi 2065d4e9bd7SPeter Ujfalusi { 2, TWL5031_BASEADD_ACCESSORY }, 2075d4e9bd7SPeter Ujfalusi { 2, TWL5031_BASEADD_INTERRUPTS }, 208b07682b6SSantosh Shilimkar }; 209b07682b6SSantosh Shilimkar 210d842b61bSKrzysztof Kozlowski static const struct reg_default twl4030_49_defaults[] = { 21191460700SPeter Ujfalusi /* Audio Registers */ 21291460700SPeter Ujfalusi { 0x01, 0x00}, /* CODEC_MODE */ 21391460700SPeter Ujfalusi { 0x02, 0x00}, /* OPTION */ 21491460700SPeter Ujfalusi /* 0x03 Unused */ 21591460700SPeter Ujfalusi { 0x04, 0x00}, /* MICBIAS_CTL */ 21691460700SPeter Ujfalusi { 0x05, 0x00}, /* ANAMICL */ 21791460700SPeter Ujfalusi { 0x06, 0x00}, /* ANAMICR */ 21891460700SPeter Ujfalusi { 0x07, 0x00}, /* AVADC_CTL */ 21991460700SPeter Ujfalusi { 0x08, 0x00}, /* ADCMICSEL */ 22091460700SPeter Ujfalusi { 0x09, 0x00}, /* DIGMIXING */ 22191460700SPeter Ujfalusi { 0x0a, 0x0f}, /* ATXL1PGA */ 22291460700SPeter Ujfalusi { 0x0b, 0x0f}, /* ATXR1PGA */ 22391460700SPeter Ujfalusi { 0x0c, 0x0f}, /* AVTXL2PGA */ 22491460700SPeter Ujfalusi { 0x0d, 0x0f}, /* AVTXR2PGA */ 22591460700SPeter Ujfalusi { 0x0e, 0x00}, /* AUDIO_IF */ 22691460700SPeter Ujfalusi { 0x0f, 0x00}, /* VOICE_IF */ 22791460700SPeter Ujfalusi { 0x10, 0x3f}, /* ARXR1PGA */ 22891460700SPeter Ujfalusi { 0x11, 0x3f}, /* ARXL1PGA */ 22991460700SPeter Ujfalusi { 0x12, 0x3f}, /* ARXR2PGA */ 23091460700SPeter Ujfalusi { 0x13, 0x3f}, /* ARXL2PGA */ 23191460700SPeter Ujfalusi { 0x14, 0x25}, /* VRXPGA */ 23291460700SPeter Ujfalusi { 0x15, 0x00}, /* VSTPGA */ 23391460700SPeter Ujfalusi { 0x16, 0x00}, /* VRX2ARXPGA */ 23491460700SPeter Ujfalusi { 0x17, 0x00}, /* AVDAC_CTL */ 23591460700SPeter Ujfalusi { 0x18, 0x00}, /* ARX2VTXPGA */ 23691460700SPeter Ujfalusi { 0x19, 0x32}, /* ARXL1_APGA_CTL*/ 23791460700SPeter Ujfalusi { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/ 23891460700SPeter Ujfalusi { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/ 23991460700SPeter Ujfalusi { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/ 24091460700SPeter Ujfalusi { 0x1d, 0x00}, /* ATX2ARXPGA */ 24191460700SPeter Ujfalusi { 0x1e, 0x00}, /* BT_IF */ 24291460700SPeter Ujfalusi { 0x1f, 0x55}, /* BTPGA */ 24391460700SPeter Ujfalusi { 0x20, 0x00}, /* BTSTPGA */ 24491460700SPeter Ujfalusi { 0x21, 0x00}, /* EAR_CTL */ 24591460700SPeter Ujfalusi { 0x22, 0x00}, /* HS_SEL */ 24691460700SPeter Ujfalusi { 0x23, 0x00}, /* HS_GAIN_SET */ 24791460700SPeter Ujfalusi { 0x24, 0x00}, /* HS_POPN_SET */ 24891460700SPeter Ujfalusi { 0x25, 0x00}, /* PREDL_CTL */ 24991460700SPeter Ujfalusi { 0x26, 0x00}, /* PREDR_CTL */ 25091460700SPeter Ujfalusi { 0x27, 0x00}, /* PRECKL_CTL */ 25191460700SPeter Ujfalusi { 0x28, 0x00}, /* PRECKR_CTL */ 25291460700SPeter Ujfalusi { 0x29, 0x00}, /* HFL_CTL */ 25391460700SPeter Ujfalusi { 0x2a, 0x00}, /* HFR_CTL */ 25491460700SPeter Ujfalusi { 0x2b, 0x05}, /* ALC_CTL */ 25591460700SPeter Ujfalusi { 0x2c, 0x00}, /* ALC_SET1 */ 25691460700SPeter Ujfalusi { 0x2d, 0x00}, /* ALC_SET2 */ 25791460700SPeter Ujfalusi { 0x2e, 0x00}, /* BOOST_CTL */ 25891460700SPeter Ujfalusi { 0x2f, 0x00}, /* SOFTVOL_CTL */ 25991460700SPeter Ujfalusi { 0x30, 0x13}, /* DTMF_FREQSEL */ 26091460700SPeter Ujfalusi { 0x31, 0x00}, /* DTMF_TONEXT1H */ 26191460700SPeter Ujfalusi { 0x32, 0x00}, /* DTMF_TONEXT1L */ 26291460700SPeter Ujfalusi { 0x33, 0x00}, /* DTMF_TONEXT2H */ 26391460700SPeter Ujfalusi { 0x34, 0x00}, /* DTMF_TONEXT2L */ 26491460700SPeter Ujfalusi { 0x35, 0x79}, /* DTMF_TONOFF */ 26591460700SPeter Ujfalusi { 0x36, 0x11}, /* DTMF_WANONOFF */ 26691460700SPeter Ujfalusi { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */ 26791460700SPeter Ujfalusi { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */ 26891460700SPeter Ujfalusi { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */ 26991460700SPeter Ujfalusi { 0x3a, 0x06}, /* APLL_CTL */ 27091460700SPeter Ujfalusi { 0x3b, 0x00}, /* DTMF_CTL */ 27191460700SPeter Ujfalusi { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */ 27291460700SPeter Ujfalusi { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */ 27391460700SPeter Ujfalusi { 0x3e, 0x00}, /* MISC_SET_1 */ 27491460700SPeter Ujfalusi { 0x3f, 0x00}, /* PCMBTMUX */ 27591460700SPeter Ujfalusi /* 0x40 - 0x42 Unused */ 27691460700SPeter Ujfalusi { 0x43, 0x00}, /* RX_PATH_SEL */ 27791460700SPeter Ujfalusi { 0x44, 0x32}, /* VDL_APGA_CTL */ 27891460700SPeter Ujfalusi { 0x45, 0x00}, /* VIBRA_CTL */ 27991460700SPeter Ujfalusi { 0x46, 0x00}, /* VIBRA_SET */ 28091460700SPeter Ujfalusi { 0x47, 0x00}, /* VIBRA_PWM_SET */ 28191460700SPeter Ujfalusi { 0x48, 0x00}, /* ANAMIC_GAIN */ 28291460700SPeter Ujfalusi { 0x49, 0x00}, /* MISC_SET_2 */ 28391460700SPeter Ujfalusi /* End of Audio Registers */ 28491460700SPeter Ujfalusi }; 28591460700SPeter Ujfalusi 28691460700SPeter Ujfalusi static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg) 28791460700SPeter Ujfalusi { 28891460700SPeter Ujfalusi switch (reg) { 28956816b70STomas Novotny case 0x00: 29056816b70STomas Novotny case 0x03: 29156816b70STomas Novotny case 0x40: 29256816b70STomas Novotny case 0x41: 29356816b70STomas Novotny case 0x42: 29491460700SPeter Ujfalusi return false; 29591460700SPeter Ujfalusi default: 29691460700SPeter Ujfalusi return true; 29791460700SPeter Ujfalusi } 29891460700SPeter Ujfalusi } 29991460700SPeter Ujfalusi 30091460700SPeter Ujfalusi static const struct regmap_range twl4030_49_volatile_ranges[] = { 30191460700SPeter Ujfalusi regmap_reg_range(TWL4030_BASEADD_TEST, 0xff), 30291460700SPeter Ujfalusi }; 30391460700SPeter Ujfalusi 30491460700SPeter Ujfalusi static const struct regmap_access_table twl4030_49_volatile_table = { 30591460700SPeter Ujfalusi .yes_ranges = twl4030_49_volatile_ranges, 30691460700SPeter Ujfalusi .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges), 30791460700SPeter Ujfalusi }; 30891460700SPeter Ujfalusi 309d842b61bSKrzysztof Kozlowski static const struct regmap_config twl4030_regmap_config[4] = { 3102473d25aSPeter Ujfalusi { 3112473d25aSPeter Ujfalusi /* Address 0x48 */ 3122473d25aSPeter Ujfalusi .reg_bits = 8, 3132473d25aSPeter Ujfalusi .val_bits = 8, 3142473d25aSPeter Ujfalusi .max_register = 0xff, 3152473d25aSPeter Ujfalusi }, 3162473d25aSPeter Ujfalusi { 3172473d25aSPeter Ujfalusi /* Address 0x49 */ 3182473d25aSPeter Ujfalusi .reg_bits = 8, 3192473d25aSPeter Ujfalusi .val_bits = 8, 3202473d25aSPeter Ujfalusi .max_register = 0xff, 32191460700SPeter Ujfalusi 32291460700SPeter Ujfalusi .readable_reg = twl4030_49_nop_reg, 32391460700SPeter Ujfalusi .writeable_reg = twl4030_49_nop_reg, 32491460700SPeter Ujfalusi 32591460700SPeter Ujfalusi .volatile_table = &twl4030_49_volatile_table, 32691460700SPeter Ujfalusi 32791460700SPeter Ujfalusi .reg_defaults = twl4030_49_defaults, 32891460700SPeter Ujfalusi .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), 32991460700SPeter Ujfalusi .cache_type = REGCACHE_RBTREE, 3302473d25aSPeter Ujfalusi }, 3312473d25aSPeter Ujfalusi { 3322473d25aSPeter Ujfalusi /* Address 0x4a */ 3332473d25aSPeter Ujfalusi .reg_bits = 8, 3342473d25aSPeter Ujfalusi .val_bits = 8, 3352473d25aSPeter Ujfalusi .max_register = 0xff, 3362473d25aSPeter Ujfalusi }, 3372473d25aSPeter Ujfalusi { 3382473d25aSPeter Ujfalusi /* Address 0x4b */ 3392473d25aSPeter Ujfalusi .reg_bits = 8, 3402473d25aSPeter Ujfalusi .val_bits = 8, 3412473d25aSPeter Ujfalusi .max_register = 0xff, 3422473d25aSPeter Ujfalusi }, 3432473d25aSPeter Ujfalusi }; 3442473d25aSPeter Ujfalusi 345e8deb28cSBalaji T K static struct twl_mapping twl6030_map[] = { 346e8deb28cSBalaji T K /* 347e8deb28cSBalaji T K * NOTE: don't change this table without updating the 348e8deb28cSBalaji T K * <linux/i2c/twl.h> defines for TWL4030_MODULE_* 349e8deb28cSBalaji T K * so they continue to match the order in this table. 350e8deb28cSBalaji T K */ 351e8deb28cSBalaji T K 3525d4e9bd7SPeter Ujfalusi /* Common IPs */ 3535d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_USB }, 3545d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_PIH }, 3555d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_CHARGER }, 3565d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_PM_MASTER }, 3575d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_PM_SLAVE_MISC }, 358e8deb28cSBalaji T K 3595d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_RTC }, 3605d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_PWM }, 3615d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_LED }, 3625d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_SECURED_REG }, 363e8deb28cSBalaji T K 3645d4e9bd7SPeter Ujfalusi /* TWL6030 specific IPs */ 3655d4e9bd7SPeter Ujfalusi { 0, TWL6030_BASEADD_ZERO }, 3665d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_ZERO }, 3675d4e9bd7SPeter Ujfalusi { 2, TWL6030_BASEADD_ZERO }, 3685d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_GPADC_CTRL }, 3695d4e9bd7SPeter Ujfalusi { 1, TWL6030_BASEADD_GASGAUGE }, 370e8deb28cSBalaji T K }; 371e8deb28cSBalaji T K 372d842b61bSKrzysztof Kozlowski static const struct regmap_config twl6030_regmap_config[3] = { 3732473d25aSPeter Ujfalusi { 3742473d25aSPeter Ujfalusi /* Address 0x48 */ 3752473d25aSPeter Ujfalusi .reg_bits = 8, 3762473d25aSPeter Ujfalusi .val_bits = 8, 3772473d25aSPeter Ujfalusi .max_register = 0xff, 3782473d25aSPeter Ujfalusi }, 3792473d25aSPeter Ujfalusi { 3802473d25aSPeter Ujfalusi /* Address 0x49 */ 3812473d25aSPeter Ujfalusi .reg_bits = 8, 3822473d25aSPeter Ujfalusi .val_bits = 8, 3832473d25aSPeter Ujfalusi .max_register = 0xff, 3842473d25aSPeter Ujfalusi }, 3852473d25aSPeter Ujfalusi { 3862473d25aSPeter Ujfalusi /* Address 0x4a */ 3872473d25aSPeter Ujfalusi .reg_bits = 8, 3882473d25aSPeter Ujfalusi .val_bits = 8, 3892473d25aSPeter Ujfalusi .max_register = 0xff, 3902473d25aSPeter Ujfalusi }, 3912473d25aSPeter Ujfalusi }; 3922473d25aSPeter Ujfalusi 393b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 394b07682b6SSantosh Shilimkar 3956dd810b5SPeter Ujfalusi static inline int twl_get_num_slaves(void) 3966dd810b5SPeter Ujfalusi { 3976dd810b5SPeter Ujfalusi if (twl_class_is_4030()) 3986dd810b5SPeter Ujfalusi return 4; /* TWL4030 class have four slave address */ 3996dd810b5SPeter Ujfalusi else 4006dd810b5SPeter Ujfalusi return 3; /* TWL6030 class have three slave address */ 4016dd810b5SPeter Ujfalusi } 4026dd810b5SPeter Ujfalusi 4035d4e9bd7SPeter Ujfalusi static inline int twl_get_last_module(void) 4045d4e9bd7SPeter Ujfalusi { 4055d4e9bd7SPeter Ujfalusi if (twl_class_is_4030()) 4065d4e9bd7SPeter Ujfalusi return TWL4030_MODULE_LAST; 4075d4e9bd7SPeter Ujfalusi else 4085d4e9bd7SPeter Ujfalusi return TWL6030_MODULE_LAST; 4095d4e9bd7SPeter Ujfalusi } 4105d4e9bd7SPeter Ujfalusi 411b07682b6SSantosh Shilimkar /* Exported Functions */ 412b07682b6SSantosh Shilimkar 41380a97ccdSPeter Ujfalusi unsigned int twl_rev(void) 41480a97ccdSPeter Ujfalusi { 41580a97ccdSPeter Ujfalusi return twl_priv ? twl_priv->twl_id : 0; 41680a97ccdSPeter Ujfalusi } 41780a97ccdSPeter Ujfalusi EXPORT_SYMBOL(twl_rev); 41880a97ccdSPeter Ujfalusi 419b07682b6SSantosh Shilimkar /** 4208daf3540SPeter Ujfalusi * twl_get_regmap - Get the regmap associated with the given module 4218daf3540SPeter Ujfalusi * @mod_no: module number 4228daf3540SPeter Ujfalusi * 4238daf3540SPeter Ujfalusi * Returns the regmap pointer or NULL in case of failure. 4248daf3540SPeter Ujfalusi */ 4258daf3540SPeter Ujfalusi static struct regmap *twl_get_regmap(u8 mod_no) 4268daf3540SPeter Ujfalusi { 4278daf3540SPeter Ujfalusi int sid; 4288daf3540SPeter Ujfalusi struct twl_client *twl; 4298daf3540SPeter Ujfalusi 4308daf3540SPeter Ujfalusi if (unlikely(!twl_priv || !twl_priv->ready)) { 4318daf3540SPeter Ujfalusi pr_err("%s: not initialized\n", DRIVER_NAME); 4328daf3540SPeter Ujfalusi return NULL; 4338daf3540SPeter Ujfalusi } 4348daf3540SPeter Ujfalusi if (unlikely(mod_no >= twl_get_last_module())) { 4358daf3540SPeter Ujfalusi pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); 4368daf3540SPeter Ujfalusi return NULL; 4378daf3540SPeter Ujfalusi } 4388daf3540SPeter Ujfalusi 4398daf3540SPeter Ujfalusi sid = twl_priv->twl_map[mod_no].sid; 4408daf3540SPeter Ujfalusi twl = &twl_priv->twl_modules[sid]; 4418daf3540SPeter Ujfalusi 4428daf3540SPeter Ujfalusi return twl->regmap; 4438daf3540SPeter Ujfalusi } 4448daf3540SPeter Ujfalusi 4458daf3540SPeter Ujfalusi /** 446fc7b92fcSBalaji T K * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 447b07682b6SSantosh Shilimkar * @mod_no: module number 448b07682b6SSantosh Shilimkar * @value: an array of num_bytes+1 containing data to write 449b07682b6SSantosh Shilimkar * @reg: register address (just offset will do) 450b07682b6SSantosh Shilimkar * @num_bytes: number of bytes to transfer 451b07682b6SSantosh Shilimkar * 452b07682b6SSantosh Shilimkar * Returns the result of operation - 0 is success 453b07682b6SSantosh Shilimkar */ 454fc7b92fcSBalaji T K int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 455b07682b6SSantosh Shilimkar { 4568daf3540SPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 457b07682b6SSantosh Shilimkar int ret; 458b07682b6SSantosh Shilimkar 4598daf3540SPeter Ujfalusi if (!regmap) 460b07682b6SSantosh Shilimkar return -EPERM; 461050cde13SPeter Ujfalusi 4628daf3540SPeter Ujfalusi ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg, 4638daf3540SPeter Ujfalusi value, num_bytes); 464b07682b6SSantosh Shilimkar 4652473d25aSPeter Ujfalusi if (ret) 4662473d25aSPeter Ujfalusi pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", 4672473d25aSPeter Ujfalusi DRIVER_NAME, mod_no, reg, num_bytes); 4682473d25aSPeter Ujfalusi 469b07682b6SSantosh Shilimkar return ret; 470b07682b6SSantosh Shilimkar } 471fc7b92fcSBalaji T K EXPORT_SYMBOL(twl_i2c_write); 472b07682b6SSantosh Shilimkar 473b07682b6SSantosh Shilimkar /** 474fc7b92fcSBalaji T K * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0 475b07682b6SSantosh Shilimkar * @mod_no: module number 476b07682b6SSantosh Shilimkar * @value: an array of num_bytes containing data to be read 477b07682b6SSantosh Shilimkar * @reg: register address (just offset will do) 478b07682b6SSantosh Shilimkar * @num_bytes: number of bytes to transfer 479b07682b6SSantosh Shilimkar * 480b07682b6SSantosh Shilimkar * Returns result of operation - num_bytes is success else failure. 481b07682b6SSantosh Shilimkar */ 482fc7b92fcSBalaji T K int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 483b07682b6SSantosh Shilimkar { 4848daf3540SPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 485b07682b6SSantosh Shilimkar int ret; 486b07682b6SSantosh Shilimkar 4878daf3540SPeter Ujfalusi if (!regmap) 488b07682b6SSantosh Shilimkar return -EPERM; 489050cde13SPeter Ujfalusi 4908daf3540SPeter Ujfalusi ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg, 4918daf3540SPeter Ujfalusi value, num_bytes); 492b07682b6SSantosh Shilimkar 4932473d25aSPeter Ujfalusi if (ret) 4942473d25aSPeter Ujfalusi pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n", 4952473d25aSPeter Ujfalusi DRIVER_NAME, mod_no, reg, num_bytes); 4962473d25aSPeter Ujfalusi 497b07682b6SSantosh Shilimkar return ret; 498b07682b6SSantosh Shilimkar } 499fc7b92fcSBalaji T K EXPORT_SYMBOL(twl_i2c_read); 500b07682b6SSantosh Shilimkar 5013def927eSPeter Ujfalusi /** 5023def927eSPeter Ujfalusi * twl_regcache_bypass - Configure the regcache bypass for the regmap associated 5033def927eSPeter Ujfalusi * with the module 5043def927eSPeter Ujfalusi * @mod_no: module number 5053def927eSPeter Ujfalusi * @enable: Regcache bypass state 5063def927eSPeter Ujfalusi * 5073def927eSPeter Ujfalusi * Returns 0 else failure. 5083def927eSPeter Ujfalusi */ 5093def927eSPeter Ujfalusi int twl_set_regcache_bypass(u8 mod_no, bool enable) 5103def927eSPeter Ujfalusi { 5113def927eSPeter Ujfalusi struct regmap *regmap = twl_get_regmap(mod_no); 5123def927eSPeter Ujfalusi 5133def927eSPeter Ujfalusi if (!regmap) 5143def927eSPeter Ujfalusi return -EPERM; 5153def927eSPeter Ujfalusi 5163def927eSPeter Ujfalusi regcache_cache_bypass(regmap, enable); 5173def927eSPeter Ujfalusi 5183def927eSPeter Ujfalusi return 0; 5193def927eSPeter Ujfalusi } 5203def927eSPeter Ujfalusi EXPORT_SYMBOL(twl_set_regcache_bypass); 5213def927eSPeter Ujfalusi 522b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 523b07682b6SSantosh Shilimkar 524ca972d13SLesly A M /** 525ca972d13SLesly A M * twl_read_idcode_register - API to read the IDCODE register. 526ca972d13SLesly A M * 527ca972d13SLesly A M * Unlocks the IDCODE register and read the 32 bit value. 528ca972d13SLesly A M */ 529ca972d13SLesly A M static int twl_read_idcode_register(void) 530ca972d13SLesly A M { 531ca972d13SLesly A M int err; 532ca972d13SLesly A M 533ca972d13SLesly A M err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK, 534ca972d13SLesly A M REG_UNLOCK_TEST_REG); 535ca972d13SLesly A M if (err) { 536ca972d13SLesly A M pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err); 537ca972d13SLesly A M goto fail; 538ca972d13SLesly A M } 539ca972d13SLesly A M 54080a97ccdSPeter Ujfalusi err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode), 541ca972d13SLesly A M REG_IDCODE_7_0, 4); 542ca972d13SLesly A M if (err) { 543ca972d13SLesly A M pr_err("TWL4030: unable to read IDCODE -%d\n", err); 544ca972d13SLesly A M goto fail; 545ca972d13SLesly A M } 546ca972d13SLesly A M 547ca972d13SLesly A M err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG); 548ca972d13SLesly A M if (err) 549ca972d13SLesly A M pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err); 550ca972d13SLesly A M fail: 551ca972d13SLesly A M return err; 552ca972d13SLesly A M } 553ca972d13SLesly A M 554ca972d13SLesly A M /** 555ca972d13SLesly A M * twl_get_type - API to get TWL Si type. 556ca972d13SLesly A M * 557ca972d13SLesly A M * Api to get the TWL Si type from IDCODE value. 558ca972d13SLesly A M */ 559ca972d13SLesly A M int twl_get_type(void) 560ca972d13SLesly A M { 56180a97ccdSPeter Ujfalusi return TWL_SIL_TYPE(twl_priv->twl_idcode); 562ca972d13SLesly A M } 563ca972d13SLesly A M EXPORT_SYMBOL_GPL(twl_get_type); 564ca972d13SLesly A M 565ca972d13SLesly A M /** 566ca972d13SLesly A M * twl_get_version - API to get TWL Si version. 567ca972d13SLesly A M * 568ca972d13SLesly A M * Api to get the TWL Si version from IDCODE value. 569ca972d13SLesly A M */ 570ca972d13SLesly A M int twl_get_version(void) 571ca972d13SLesly A M { 57280a97ccdSPeter Ujfalusi return TWL_SIL_REV(twl_priv->twl_idcode); 573ca972d13SLesly A M } 574ca972d13SLesly A M EXPORT_SYMBOL_GPL(twl_get_version); 575ca972d13SLesly A M 5762275c544SPeter Ujfalusi /** 5772275c544SPeter Ujfalusi * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. 5782275c544SPeter Ujfalusi * 5792275c544SPeter Ujfalusi * Api to get the TWL HFCLK rate based on BOOT_CFG register. 5802275c544SPeter Ujfalusi */ 5812275c544SPeter Ujfalusi int twl_get_hfclk_rate(void) 5822275c544SPeter Ujfalusi { 5832275c544SPeter Ujfalusi u8 ctrl; 5842275c544SPeter Ujfalusi int rate; 5852275c544SPeter Ujfalusi 5862275c544SPeter Ujfalusi twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); 5872275c544SPeter Ujfalusi 5882275c544SPeter Ujfalusi switch (ctrl & 0x3) { 5892275c544SPeter Ujfalusi case HFCLK_FREQ_19p2_MHZ: 5902275c544SPeter Ujfalusi rate = 19200000; 5912275c544SPeter Ujfalusi break; 5922275c544SPeter Ujfalusi case HFCLK_FREQ_26_MHZ: 5932275c544SPeter Ujfalusi rate = 26000000; 5942275c544SPeter Ujfalusi break; 5952275c544SPeter Ujfalusi case HFCLK_FREQ_38p4_MHZ: 5962275c544SPeter Ujfalusi rate = 38400000; 5972275c544SPeter Ujfalusi break; 5982275c544SPeter Ujfalusi default: 5992275c544SPeter Ujfalusi pr_err("TWL4030: HFCLK is not configured\n"); 6002275c544SPeter Ujfalusi rate = -EINVAL; 6012275c544SPeter Ujfalusi break; 6022275c544SPeter Ujfalusi } 6032275c544SPeter Ujfalusi 6042275c544SPeter Ujfalusi return rate; 6052275c544SPeter Ujfalusi } 6062275c544SPeter Ujfalusi EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); 6072275c544SPeter Ujfalusi 608b07682b6SSantosh Shilimkar static struct device * 6093c330279SPeter Ujfalusi add_numbered_child(unsigned mod_no, const char *name, int num, 610b07682b6SSantosh Shilimkar void *pdata, unsigned pdata_len, 611b07682b6SSantosh Shilimkar bool can_wakeup, int irq0, int irq1) 612b07682b6SSantosh Shilimkar { 613b07682b6SSantosh Shilimkar struct platform_device *pdev; 6143c330279SPeter Ujfalusi struct twl_client *twl; 6153c330279SPeter Ujfalusi int status, sid; 6163c330279SPeter Ujfalusi 6173c330279SPeter Ujfalusi if (unlikely(mod_no >= twl_get_last_module())) { 6183c330279SPeter Ujfalusi pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); 6193c330279SPeter Ujfalusi return ERR_PTR(-EPERM); 6203c330279SPeter Ujfalusi } 62180a97ccdSPeter Ujfalusi sid = twl_priv->twl_map[mod_no].sid; 62280a97ccdSPeter Ujfalusi twl = &twl_priv->twl_modules[sid]; 623b07682b6SSantosh Shilimkar 624b07682b6SSantosh Shilimkar pdev = platform_device_alloc(name, num); 625a67911d3SMarkus Elfring if (!pdev) 626a67911d3SMarkus Elfring return ERR_PTR(-ENOMEM); 627b07682b6SSantosh Shilimkar 628b07682b6SSantosh Shilimkar pdev->dev.parent = &twl->client->dev; 629b07682b6SSantosh Shilimkar 630b07682b6SSantosh Shilimkar if (pdata) { 631b07682b6SSantosh Shilimkar status = platform_device_add_data(pdev, pdata, pdata_len); 632b07682b6SSantosh Shilimkar if (status < 0) { 633b07682b6SSantosh Shilimkar dev_dbg(&pdev->dev, "can't add platform_data\n"); 6348175a01cSMarkus Elfring goto put_device; 635b07682b6SSantosh Shilimkar } 636b07682b6SSantosh Shilimkar } 637b07682b6SSantosh Shilimkar 638b07682b6SSantosh Shilimkar if (irq0) { 639b07682b6SSantosh Shilimkar struct resource r[2] = { 640b07682b6SSantosh Shilimkar { .start = irq0, .flags = IORESOURCE_IRQ, }, 641b07682b6SSantosh Shilimkar { .start = irq1, .flags = IORESOURCE_IRQ, }, 642b07682b6SSantosh Shilimkar }; 643b07682b6SSantosh Shilimkar 644b07682b6SSantosh Shilimkar status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1); 645b07682b6SSantosh Shilimkar if (status < 0) { 646b07682b6SSantosh Shilimkar dev_dbg(&pdev->dev, "can't add irqs\n"); 6478175a01cSMarkus Elfring goto put_device; 648b07682b6SSantosh Shilimkar } 649b07682b6SSantosh Shilimkar } 650b07682b6SSantosh Shilimkar 651b07682b6SSantosh Shilimkar status = platform_device_add(pdev); 6528175a01cSMarkus Elfring if (status) 6538175a01cSMarkus Elfring goto put_device; 6548175a01cSMarkus Elfring 65517ffba6aSNeilBrown device_init_wakeup(&pdev->dev, can_wakeup); 656b07682b6SSantosh Shilimkar 657b07682b6SSantosh Shilimkar return &pdev->dev; 6588175a01cSMarkus Elfring 6598175a01cSMarkus Elfring put_device: 6608175a01cSMarkus Elfring platform_device_put(pdev); 6618175a01cSMarkus Elfring dev_err(&twl->client->dev, "failed to add device %s\n", name); 6628175a01cSMarkus Elfring return ERR_PTR(status); 663b07682b6SSantosh Shilimkar } 664b07682b6SSantosh Shilimkar 6653c330279SPeter Ujfalusi static inline struct device *add_child(unsigned mod_no, const char *name, 666b07682b6SSantosh Shilimkar void *pdata, unsigned pdata_len, 667b07682b6SSantosh Shilimkar bool can_wakeup, int irq0, int irq1) 668b07682b6SSantosh Shilimkar { 6693c330279SPeter Ujfalusi return add_numbered_child(mod_no, name, -1, pdata, pdata_len, 670b07682b6SSantosh Shilimkar can_wakeup, irq0, irq1); 671b07682b6SSantosh Shilimkar } 672b07682b6SSantosh Shilimkar 673b07682b6SSantosh Shilimkar static struct device * 674b07682b6SSantosh Shilimkar add_regulator_linked(int num, struct regulator_init_data *pdata, 675b07682b6SSantosh Shilimkar struct regulator_consumer_supply *consumers, 676521d8ec3SGraeme Gregory unsigned num_consumers, unsigned long features) 677b07682b6SSantosh Shilimkar { 67863bfff4eSTero Kristo struct twl_regulator_driver_data drv_data; 67963bfff4eSTero Kristo 680b07682b6SSantosh Shilimkar /* regulator framework demands init_data ... */ 681b07682b6SSantosh Shilimkar if (!pdata) 682b07682b6SSantosh Shilimkar return NULL; 683b07682b6SSantosh Shilimkar 684b07682b6SSantosh Shilimkar if (consumers) { 685b07682b6SSantosh Shilimkar pdata->consumer_supplies = consumers; 686b07682b6SSantosh Shilimkar pdata->num_consumer_supplies = num_consumers; 687b07682b6SSantosh Shilimkar } 688b07682b6SSantosh Shilimkar 68963bfff4eSTero Kristo if (pdata->driver_data) { 69063bfff4eSTero Kristo /* If we have existing drv_data, just add the flags */ 69163bfff4eSTero Kristo struct twl_regulator_driver_data *tmp; 69263bfff4eSTero Kristo tmp = pdata->driver_data; 69363bfff4eSTero Kristo tmp->features |= features; 69463bfff4eSTero Kristo } else { 69563bfff4eSTero Kristo /* add new driver data struct, used only during init */ 69663bfff4eSTero Kristo drv_data.features = features; 69763bfff4eSTero Kristo drv_data.set_voltage = NULL; 69863bfff4eSTero Kristo drv_data.get_voltage = NULL; 69963bfff4eSTero Kristo drv_data.data = NULL; 70063bfff4eSTero Kristo pdata->driver_data = &drv_data; 70163bfff4eSTero Kristo } 702521d8ec3SGraeme Gregory 703b07682b6SSantosh Shilimkar /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ 7043c330279SPeter Ujfalusi return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num, 705b07682b6SSantosh Shilimkar pdata, sizeof(*pdata), false, 0, 0); 706b07682b6SSantosh Shilimkar } 707b07682b6SSantosh Shilimkar 708b07682b6SSantosh Shilimkar static struct device * 709521d8ec3SGraeme Gregory add_regulator(int num, struct regulator_init_data *pdata, 710521d8ec3SGraeme Gregory unsigned long features) 711b07682b6SSantosh Shilimkar { 712521d8ec3SGraeme Gregory return add_regulator_linked(num, pdata, NULL, 0, features); 713b07682b6SSantosh Shilimkar } 714b07682b6SSantosh Shilimkar 715b07682b6SSantosh Shilimkar /* 716b07682b6SSantosh Shilimkar * NOTE: We know the first 8 IRQs after pdata->base_irq are 717b07682b6SSantosh Shilimkar * for the PIH, and the next are for the PWR_INT SIH, since 718b07682b6SSantosh Shilimkar * that's how twl_init_irq() sets things up. 719b07682b6SSantosh Shilimkar */ 720b07682b6SSantosh Shilimkar 721b07682b6SSantosh Shilimkar static int 7229e178620SFelipe Balbi add_children(struct twl4030_platform_data *pdata, unsigned irq_base, 7239e178620SFelipe Balbi unsigned long features) 724b07682b6SSantosh Shilimkar { 725b07682b6SSantosh Shilimkar struct device *child; 726b07682b6SSantosh Shilimkar 727f78959cfSThierry Reding if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { 7283c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio", 729b07682b6SSantosh Shilimkar pdata->gpio, sizeof(*pdata->gpio), 7309e178620SFelipe Balbi false, irq_base + GPIO_INTR_OFFSET, 0); 731b07682b6SSantosh Shilimkar if (IS_ERR(child)) 732b07682b6SSantosh Shilimkar return PTR_ERR(child); 733b07682b6SSantosh Shilimkar } 734b07682b6SSantosh Shilimkar 735f78959cfSThierry Reding if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { 7363c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad", 737b07682b6SSantosh Shilimkar pdata->keypad, sizeof(*pdata->keypad), 7389e178620SFelipe Balbi true, irq_base + KEYPAD_INTR_OFFSET, 0); 739b07682b6SSantosh Shilimkar if (IS_ERR(child)) 740b07682b6SSantosh Shilimkar return PTR_ERR(child); 741b07682b6SSantosh Shilimkar } 742b07682b6SSantosh Shilimkar 74324ae36f5SPeter Ujfalusi if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc && 74424ae36f5SPeter Ujfalusi twl_class_is_4030()) { 7453c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_MADC, "twl4030_madc", 746b07682b6SSantosh Shilimkar pdata->madc, sizeof(*pdata->madc), 7479e178620SFelipe Balbi true, irq_base + MADC_INTR_OFFSET, 0); 748b07682b6SSantosh Shilimkar if (IS_ERR(child)) 749b07682b6SSantosh Shilimkar return PTR_ERR(child); 750b07682b6SSantosh Shilimkar } 751b07682b6SSantosh Shilimkar 752f78959cfSThierry Reding if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { 753b07682b6SSantosh Shilimkar /* 754b07682b6SSantosh Shilimkar * REVISIT platform_data here currently might expose the 755b07682b6SSantosh Shilimkar * "msecure" line ... but for now we just expect board 756b07682b6SSantosh Shilimkar * setup to tell the chip "it's always ok to SET_TIME". 757b07682b6SSantosh Shilimkar * Eventually, Linux might become more aware of such 758b07682b6SSantosh Shilimkar * HW security concerns, and "least privilege". 759b07682b6SSantosh Shilimkar */ 7603c330279SPeter Ujfalusi child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0, 7619e178620SFelipe Balbi true, irq_base + RTC_INTR_OFFSET, 0); 762b07682b6SSantosh Shilimkar if (IS_ERR(child)) 763b07682b6SSantosh Shilimkar return PTR_ERR(child); 764b07682b6SSantosh Shilimkar } 765b07682b6SSantosh Shilimkar 766afc45898SPeter Ujfalusi if (IS_ENABLED(CONFIG_PWM_TWL)) { 7673c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0, 768afc45898SPeter Ujfalusi false, 0, 0); 769afc45898SPeter Ujfalusi if (IS_ERR(child)) 770afc45898SPeter Ujfalusi return PTR_ERR(child); 771afc45898SPeter Ujfalusi } 772afc45898SPeter Ujfalusi 773afc45898SPeter Ujfalusi if (IS_ENABLED(CONFIG_PWM_TWL_LED)) { 7743c330279SPeter Ujfalusi child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0, 77548a364b7SThierry Reding false, 0, 0); 77648a364b7SThierry Reding if (IS_ERR(child)) 77748a364b7SThierry Reding return PTR_ERR(child); 77848a364b7SThierry Reding } 77948a364b7SThierry Reding 780f78959cfSThierry Reding if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && 781f78959cfSThierry Reding twl_class_is_4030()) { 782b07682b6SSantosh Shilimkar 783b07682b6SSantosh Shilimkar static struct regulator_consumer_supply usb1v5 = { 784b07682b6SSantosh Shilimkar .supply = "usb1v5", 785b07682b6SSantosh Shilimkar }; 786b07682b6SSantosh Shilimkar static struct regulator_consumer_supply usb1v8 = { 787b07682b6SSantosh Shilimkar .supply = "usb1v8", 788b07682b6SSantosh Shilimkar }; 789e57c4a67SNeilBrown static struct regulator_consumer_supply usb3v1 = { 790e57c4a67SNeilBrown .supply = "usb3v1", 791b07682b6SSantosh Shilimkar }; 792b07682b6SSantosh Shilimkar 793b07682b6SSantosh Shilimkar /* First add the regulators so that they can be used by transceiver */ 794f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { 795b07682b6SSantosh Shilimkar /* this is a template that gets copied */ 796b07682b6SSantosh Shilimkar struct regulator_init_data usb_fixed = { 797b07682b6SSantosh Shilimkar .constraints.valid_modes_mask = 798b07682b6SSantosh Shilimkar REGULATOR_MODE_NORMAL 799b07682b6SSantosh Shilimkar | REGULATOR_MODE_STANDBY, 800b07682b6SSantosh Shilimkar .constraints.valid_ops_mask = 801b07682b6SSantosh Shilimkar REGULATOR_CHANGE_MODE 802b07682b6SSantosh Shilimkar | REGULATOR_CHANGE_STATUS, 803b07682b6SSantosh Shilimkar }; 804b07682b6SSantosh Shilimkar 805b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB1V5, 806521d8ec3SGraeme Gregory &usb_fixed, &usb1v5, 1, 807521d8ec3SGraeme Gregory features); 808b07682b6SSantosh Shilimkar if (IS_ERR(child)) 809b07682b6SSantosh Shilimkar return PTR_ERR(child); 810b07682b6SSantosh Shilimkar 811b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB1V8, 812521d8ec3SGraeme Gregory &usb_fixed, &usb1v8, 1, 813521d8ec3SGraeme Gregory features); 814b07682b6SSantosh Shilimkar if (IS_ERR(child)) 815b07682b6SSantosh Shilimkar return PTR_ERR(child); 816b07682b6SSantosh Shilimkar 817b07682b6SSantosh Shilimkar child = add_regulator_linked(TWL4030_REG_VUSB3V1, 818e57c4a67SNeilBrown &usb_fixed, &usb3v1, 1, 819521d8ec3SGraeme Gregory features); 820b07682b6SSantosh Shilimkar if (IS_ERR(child)) 821b07682b6SSantosh Shilimkar return PTR_ERR(child); 822b07682b6SSantosh Shilimkar 823b07682b6SSantosh Shilimkar } 824b07682b6SSantosh Shilimkar 8253c330279SPeter Ujfalusi child = add_child(TWL_MODULE_USB, "twl4030_usb", 8262d86ad37SPeter Ujfalusi pdata->usb, sizeof(*pdata->usb), true, 827b07682b6SSantosh Shilimkar /* irq0 = USB_PRES, irq1 = USB */ 8289e178620SFelipe Balbi irq_base + USB_PRES_INTR_OFFSET, 8299e178620SFelipe Balbi irq_base + USB_INTR_OFFSET); 830b07682b6SSantosh Shilimkar 831b07682b6SSantosh Shilimkar if (IS_ERR(child)) 832b07682b6SSantosh Shilimkar return PTR_ERR(child); 833b07682b6SSantosh Shilimkar 834b07682b6SSantosh Shilimkar /* we need to connect regulators to this transceiver */ 835f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { 8361b65fa84SMark Brown usb1v5.dev_name = dev_name(child); 8371b65fa84SMark Brown usb1v8.dev_name = dev_name(child); 838e57c4a67SNeilBrown usb3v1.dev_name = dev_name(child); 839b07682b6SSantosh Shilimkar } 840b07682b6SSantosh Shilimkar } 841b07682b6SSantosh Shilimkar 842f78959cfSThierry Reding if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { 8433c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL, 8443c330279SPeter Ujfalusi 0, false, 0, 0); 845b07682b6SSantosh Shilimkar if (IS_ERR(child)) 846b07682b6SSantosh Shilimkar return PTR_ERR(child); 847b07682b6SSantosh Shilimkar } 848b07682b6SSantosh Shilimkar 849f78959cfSThierry Reding if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { 8503c330279SPeter Ujfalusi child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton", 8513c330279SPeter Ujfalusi NULL, 0, true, irq_base + 8 + 0, 0); 852b07682b6SSantosh Shilimkar if (IS_ERR(child)) 853b07682b6SSantosh Shilimkar return PTR_ERR(child); 854b07682b6SSantosh Shilimkar } 855b07682b6SSantosh Shilimkar 856f78959cfSThierry Reding if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && 857f78959cfSThierry Reding twl_class_is_4030()) { 8583c330279SPeter Ujfalusi child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio", 8594ae6df5eSPeter Ujfalusi pdata->audio, sizeof(*pdata->audio), 860d62abe56SMisael Lopez Cruz false, 0, 0); 861d62abe56SMisael Lopez Cruz if (IS_ERR(child)) 862d62abe56SMisael Lopez Cruz return PTR_ERR(child); 863d62abe56SMisael Lopez Cruz } 864d62abe56SMisael Lopez Cruz 8659da66539SRajendra Nayak /* twl4030 regulators */ 866f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { 867521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, 868521d8ec3SGraeme Gregory features); 869b07682b6SSantosh Shilimkar if (IS_ERR(child)) 870b07682b6SSantosh Shilimkar return PTR_ERR(child); 871b07682b6SSantosh Shilimkar 872521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VIO, pdata->vio, 873521d8ec3SGraeme Gregory features); 874b07682b6SSantosh Shilimkar if (IS_ERR(child)) 875b07682b6SSantosh Shilimkar return PTR_ERR(child); 876b07682b6SSantosh Shilimkar 877521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1, 878521d8ec3SGraeme Gregory features); 879b07682b6SSantosh Shilimkar if (IS_ERR(child)) 880b07682b6SSantosh Shilimkar return PTR_ERR(child); 881b07682b6SSantosh Shilimkar 882521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2, 883521d8ec3SGraeme Gregory features); 884b07682b6SSantosh Shilimkar if (IS_ERR(child)) 885b07682b6SSantosh Shilimkar return PTR_ERR(child); 886b07682b6SSantosh Shilimkar 887521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1, 888521d8ec3SGraeme Gregory features); 889b07682b6SSantosh Shilimkar if (IS_ERR(child)) 890b07682b6SSantosh Shilimkar return PTR_ERR(child); 891b07682b6SSantosh Shilimkar 892521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VDAC, pdata->vdac, 893521d8ec3SGraeme Gregory features); 894b07682b6SSantosh Shilimkar if (IS_ERR(child)) 895b07682b6SSantosh Shilimkar return PTR_ERR(child); 896b07682b6SSantosh Shilimkar 897b07682b6SSantosh Shilimkar child = add_regulator((features & TWL4030_VAUX2) 898b07682b6SSantosh Shilimkar ? TWL4030_REG_VAUX2_4030 899b07682b6SSantosh Shilimkar : TWL4030_REG_VAUX2, 900521d8ec3SGraeme Gregory pdata->vaux2, features); 901b07682b6SSantosh Shilimkar if (IS_ERR(child)) 902b07682b6SSantosh Shilimkar return PTR_ERR(child); 903b07682b6SSantosh Shilimkar 904521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1, 905521d8ec3SGraeme Gregory features); 906b07682b6SSantosh Shilimkar if (IS_ERR(child)) 907b07682b6SSantosh Shilimkar return PTR_ERR(child); 908b07682b6SSantosh Shilimkar 909521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2, 910521d8ec3SGraeme Gregory features); 911b07682b6SSantosh Shilimkar if (IS_ERR(child)) 912b07682b6SSantosh Shilimkar return PTR_ERR(child); 913b07682b6SSantosh Shilimkar 914521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig, 915521d8ec3SGraeme Gregory features); 916b07682b6SSantosh Shilimkar if (IS_ERR(child)) 917b07682b6SSantosh Shilimkar return PTR_ERR(child); 918b07682b6SSantosh Shilimkar } 919b07682b6SSantosh Shilimkar 920b07682b6SSantosh Shilimkar /* maybe add LDOs that are omitted on cost-reduced parts */ 921f78959cfSThierry Reding if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) 9229da66539SRajendra Nayak && twl_class_is_4030()) { 923521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, 924521d8ec3SGraeme Gregory features); 925b07682b6SSantosh Shilimkar if (IS_ERR(child)) 926b07682b6SSantosh Shilimkar return PTR_ERR(child); 927b07682b6SSantosh Shilimkar 928521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2, 929521d8ec3SGraeme Gregory features); 930b07682b6SSantosh Shilimkar if (IS_ERR(child)) 931b07682b6SSantosh Shilimkar return PTR_ERR(child); 932b07682b6SSantosh Shilimkar 933521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VSIM, pdata->vsim, 934521d8ec3SGraeme Gregory features); 935b07682b6SSantosh Shilimkar if (IS_ERR(child)) 936b07682b6SSantosh Shilimkar return PTR_ERR(child); 937b07682b6SSantosh Shilimkar 938521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1, 939521d8ec3SGraeme Gregory features); 940b07682b6SSantosh Shilimkar if (IS_ERR(child)) 941b07682b6SSantosh Shilimkar return PTR_ERR(child); 942b07682b6SSantosh Shilimkar 943521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3, 944521d8ec3SGraeme Gregory features); 945b07682b6SSantosh Shilimkar if (IS_ERR(child)) 946b07682b6SSantosh Shilimkar return PTR_ERR(child); 947b07682b6SSantosh Shilimkar 948521d8ec3SGraeme Gregory child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4, 949521d8ec3SGraeme Gregory features); 950b07682b6SSantosh Shilimkar if (IS_ERR(child)) 951b07682b6SSantosh Shilimkar return PTR_ERR(child); 952b07682b6SSantosh Shilimkar } 953b07682b6SSantosh Shilimkar 954f78959cfSThierry Reding if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && 95511c39c4bSGrazvydas Ignotas !(features & (TPS_SUBSET | TWL5031))) { 9563c330279SPeter Ujfalusi child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci", 95711c39c4bSGrazvydas Ignotas pdata->bci, sizeof(*pdata->bci), false, 95811c39c4bSGrazvydas Ignotas /* irq0 = CHG_PRES, irq1 = BCI */ 9599e178620SFelipe Balbi irq_base + BCI_PRES_INTR_OFFSET, 9609e178620SFelipe Balbi irq_base + BCI_INTR_OFFSET); 96111c39c4bSGrazvydas Ignotas if (IS_ERR(child)) 96211c39c4bSGrazvydas Ignotas return PTR_ERR(child); 96311c39c4bSGrazvydas Ignotas } 96411c39c4bSGrazvydas Ignotas 965637d6895SFlorian Vaussard if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) { 966637d6895SFlorian Vaussard child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power", 967637d6895SFlorian Vaussard pdata->power, sizeof(*pdata->power), false, 968637d6895SFlorian Vaussard 0, 0); 969637d6895SFlorian Vaussard if (IS_ERR(child)) 970637d6895SFlorian Vaussard return PTR_ERR(child); 971637d6895SFlorian Vaussard } 972637d6895SFlorian Vaussard 973b07682b6SSantosh Shilimkar return 0; 974b07682b6SSantosh Shilimkar } 975b07682b6SSantosh Shilimkar 976b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 977b07682b6SSantosh Shilimkar 978b07682b6SSantosh Shilimkar /* 979b07682b6SSantosh Shilimkar * These three functions initialize the on-chip clock framework, 980b07682b6SSantosh Shilimkar * letting it generate the right frequencies for USB, MADC, and 981b07682b6SSantosh Shilimkar * other purposes. 982b07682b6SSantosh Shilimkar */ 983b07682b6SSantosh Shilimkar static inline int __init protect_pm_master(void) 984b07682b6SSantosh Shilimkar { 985b07682b6SSantosh Shilimkar int e = 0; 986b07682b6SSantosh Shilimkar 987d640e757SPeter Ujfalusi e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, 98849e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 989b07682b6SSantosh Shilimkar return e; 990b07682b6SSantosh Shilimkar } 991b07682b6SSantosh Shilimkar 992b07682b6SSantosh Shilimkar static inline int __init unprotect_pm_master(void) 993b07682b6SSantosh Shilimkar { 994b07682b6SSantosh Shilimkar int e = 0; 995b07682b6SSantosh Shilimkar 996d640e757SPeter Ujfalusi e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, 99749e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 998d640e757SPeter Ujfalusi e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, 99949e6f87eSFelipe Balbi TWL4030_PM_MASTER_PROTECT_KEY); 100049e6f87eSFelipe Balbi 1001b07682b6SSantosh Shilimkar return e; 1002b07682b6SSantosh Shilimkar } 1003b07682b6SSantosh Shilimkar 1004b07682b6SSantosh Shilimkar static void clocks_init(struct device *dev, 1005b07682b6SSantosh Shilimkar struct twl4030_clock_init_data *clock) 1006b07682b6SSantosh Shilimkar { 1007b07682b6SSantosh Shilimkar int e = 0; 1008b07682b6SSantosh Shilimkar struct clk *osc; 1009b07682b6SSantosh Shilimkar u32 rate; 1010b07682b6SSantosh Shilimkar u8 ctrl = HFCLK_FREQ_26_MHZ; 1011b07682b6SSantosh Shilimkar 1012defa6be1STony Lindgren osc = clk_get(dev, "fck"); 1013b07682b6SSantosh Shilimkar if (IS_ERR(osc)) { 1014fc7b92fcSBalaji T K printk(KERN_WARNING "Skipping twl internal clock init and " 1015b07682b6SSantosh Shilimkar "using bootloader value (unknown osc rate)\n"); 1016b07682b6SSantosh Shilimkar return; 1017b07682b6SSantosh Shilimkar } 1018b07682b6SSantosh Shilimkar 1019b07682b6SSantosh Shilimkar rate = clk_get_rate(osc); 1020b07682b6SSantosh Shilimkar clk_put(osc); 1021b07682b6SSantosh Shilimkar 1022b07682b6SSantosh Shilimkar switch (rate) { 1023b07682b6SSantosh Shilimkar case 19200000: 1024b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_19p2_MHZ; 1025b07682b6SSantosh Shilimkar break; 1026b07682b6SSantosh Shilimkar case 26000000: 1027b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_26_MHZ; 1028b07682b6SSantosh Shilimkar break; 1029b07682b6SSantosh Shilimkar case 38400000: 1030b07682b6SSantosh Shilimkar ctrl = HFCLK_FREQ_38p4_MHZ; 1031b07682b6SSantosh Shilimkar break; 1032b07682b6SSantosh Shilimkar } 1033b07682b6SSantosh Shilimkar 1034b07682b6SSantosh Shilimkar ctrl |= HIGH_PERF_SQ; 1035b07682b6SSantosh Shilimkar if (clock && clock->ck32k_lowpwr_enable) 1036b07682b6SSantosh Shilimkar ctrl |= CK32K_LOWPWR_EN; 1037b07682b6SSantosh Shilimkar 1038b07682b6SSantosh Shilimkar e |= unprotect_pm_master(); 1039b07682b6SSantosh Shilimkar /* effect->MADC+USB ck en */ 1040fc7b92fcSBalaji T K e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); 1041b07682b6SSantosh Shilimkar e |= protect_pm_master(); 1042b07682b6SSantosh Shilimkar 1043b07682b6SSantosh Shilimkar if (e < 0) 1044b07682b6SSantosh Shilimkar pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e); 1045b07682b6SSantosh Shilimkar } 1046b07682b6SSantosh Shilimkar 1047b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 1048b07682b6SSantosh Shilimkar 1049b07682b6SSantosh Shilimkar 1050fc7b92fcSBalaji T K static int twl_remove(struct i2c_client *client) 1051b07682b6SSantosh Shilimkar { 1052364cedb2SPeter Ujfalusi unsigned i, num_slaves; 1053b07682b6SSantosh Shilimkar int status; 1054b07682b6SSantosh Shilimkar 10556dd810b5SPeter Ujfalusi if (twl_class_is_4030()) 1056e8deb28cSBalaji T K status = twl4030_exit_irq(); 10576dd810b5SPeter Ujfalusi else 1058e8deb28cSBalaji T K status = twl6030_exit_irq(); 1059e8deb28cSBalaji T K 1060b07682b6SSantosh Shilimkar if (status < 0) 1061b07682b6SSantosh Shilimkar return status; 1062b07682b6SSantosh Shilimkar 10636dd810b5SPeter Ujfalusi num_slaves = twl_get_num_slaves(); 1064364cedb2SPeter Ujfalusi for (i = 0; i < num_slaves; i++) { 106580a97ccdSPeter Ujfalusi struct twl_client *twl = &twl_priv->twl_modules[i]; 1066b07682b6SSantosh Shilimkar 1067b07682b6SSantosh Shilimkar if (twl->client && twl->client != client) 1068b07682b6SSantosh Shilimkar i2c_unregister_device(twl->client); 106980a97ccdSPeter Ujfalusi twl->client = NULL; 1070b07682b6SSantosh Shilimkar } 107180a97ccdSPeter Ujfalusi twl_priv->ready = false; 1072b07682b6SSantosh Shilimkar return 0; 1073b07682b6SSantosh Shilimkar } 1074b07682b6SSantosh Shilimkar 107580ec831eSTony Lindgren static struct of_dev_auxdata twl_auxdata_lookup[] = { 107680ec831eSTony Lindgren OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), 107780ec831eSTony Lindgren { /* sentinel */ }, 107880ec831eSTony Lindgren }; 107980ec831eSTony Lindgren 1080ec1a07b3SBenoit Cousson /* NOTE: This driver only handles a single twl4030/tps659x0 chip */ 1081f791be49SBill Pemberton static int 1082fc7b92fcSBalaji T K twl_probe(struct i2c_client *client, const struct i2c_device_id *id) 1083b07682b6SSantosh Shilimkar { 1084334a41ceSJingoo Han struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev); 1085aeb5032bSBenoit Cousson struct device_node *node = client->dev.of_node; 1086defa6be1STony Lindgren struct platform_device *pdev; 1087d842b61bSKrzysztof Kozlowski const struct regmap_config *twl_regmap_config; 1088ec1a07b3SBenoit Cousson int irq_base = 0; 1089ec1a07b3SBenoit Cousson int status; 1090364cedb2SPeter Ujfalusi unsigned i, num_slaves; 1091aeb5032bSBenoit Cousson 10927e2e6c57SPeter Ujfalusi if (!node && !pdata) { 10937e2e6c57SPeter Ujfalusi dev_err(&client->dev, "no platform data\n"); 10947e2e6c57SPeter Ujfalusi return -EINVAL; 10957e2e6c57SPeter Ujfalusi } 10967e2e6c57SPeter Ujfalusi 109780a97ccdSPeter Ujfalusi if (twl_priv) { 10986382a061SPeter Ujfalusi dev_dbg(&client->dev, "only one instance of %s allowed\n", 10996382a061SPeter Ujfalusi DRIVER_NAME); 11006382a061SPeter Ujfalusi return -EBUSY; 11016382a061SPeter Ujfalusi } 11026382a061SPeter Ujfalusi 1103defa6be1STony Lindgren pdev = platform_device_alloc(DRIVER_NAME, -1); 1104defa6be1STony Lindgren if (!pdev) { 1105defa6be1STony Lindgren dev_err(&client->dev, "can't alloc pdev\n"); 1106defa6be1STony Lindgren return -ENOMEM; 1107defa6be1STony Lindgren } 1108defa6be1STony Lindgren 1109defa6be1STony Lindgren status = platform_device_add(pdev); 1110defa6be1STony Lindgren if (status) { 1111defa6be1STony Lindgren platform_device_put(pdev); 1112defa6be1STony Lindgren return status; 1113defa6be1STony Lindgren } 1114defa6be1STony Lindgren 1115b07682b6SSantosh Shilimkar if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { 1116b07682b6SSantosh Shilimkar dev_dbg(&client->dev, "can't talk I2C?\n"); 1117defa6be1STony Lindgren status = -EIO; 1118defa6be1STony Lindgren goto free; 1119b07682b6SSantosh Shilimkar } 1120b07682b6SSantosh Shilimkar 112180a97ccdSPeter Ujfalusi twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private), 112280a97ccdSPeter Ujfalusi GFP_KERNEL); 112380a97ccdSPeter Ujfalusi if (!twl_priv) { 112480a97ccdSPeter Ujfalusi status = -ENOMEM; 112580a97ccdSPeter Ujfalusi goto free; 112680a97ccdSPeter Ujfalusi } 112780a97ccdSPeter Ujfalusi 1128364cedb2SPeter Ujfalusi if ((id->driver_data) & TWL6030_CLASS) { 112980a97ccdSPeter Ujfalusi twl_priv->twl_id = TWL6030_CLASS_ID; 113080a97ccdSPeter Ujfalusi twl_priv->twl_map = &twl6030_map[0]; 113189ce43fbSGraeme Gregory /* The charger base address is different in twl6032 */ 113289ce43fbSGraeme Gregory if ((id->driver_data) & TWL6032_SUBCLASS) 113380a97ccdSPeter Ujfalusi twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base = 113489ce43fbSGraeme Gregory TWL6032_BASEADD_CHARGER; 11352473d25aSPeter Ujfalusi twl_regmap_config = twl6030_regmap_config; 1136364cedb2SPeter Ujfalusi } else { 113780a97ccdSPeter Ujfalusi twl_priv->twl_id = TWL4030_CLASS_ID; 113880a97ccdSPeter Ujfalusi twl_priv->twl_map = &twl4030_map[0]; 11392473d25aSPeter Ujfalusi twl_regmap_config = twl4030_regmap_config; 11406dd810b5SPeter Ujfalusi } 11416dd810b5SPeter Ujfalusi 11426dd810b5SPeter Ujfalusi num_slaves = twl_get_num_slaves(); 114380a97ccdSPeter Ujfalusi twl_priv->twl_modules = devm_kzalloc(&client->dev, 11446dd810b5SPeter Ujfalusi sizeof(struct twl_client) * num_slaves, 11456dd810b5SPeter Ujfalusi GFP_KERNEL); 114680a97ccdSPeter Ujfalusi if (!twl_priv->twl_modules) { 11476dd810b5SPeter Ujfalusi status = -ENOMEM; 11486dd810b5SPeter Ujfalusi goto free; 1149364cedb2SPeter Ujfalusi } 1150364cedb2SPeter Ujfalusi 1151364cedb2SPeter Ujfalusi for (i = 0; i < num_slaves; i++) { 115280a97ccdSPeter Ujfalusi struct twl_client *twl = &twl_priv->twl_modules[i]; 1153b07682b6SSantosh Shilimkar 1154ec1a07b3SBenoit Cousson if (i == 0) { 1155b07682b6SSantosh Shilimkar twl->client = client; 1156ec1a07b3SBenoit Cousson } else { 1157b07682b6SSantosh Shilimkar twl->client = i2c_new_dummy(client->adapter, 11582473d25aSPeter Ujfalusi client->addr + i); 1159b07682b6SSantosh Shilimkar if (!twl->client) { 1160b07682b6SSantosh Shilimkar dev_err(&client->dev, 1161b07682b6SSantosh Shilimkar "can't attach client %d\n", i); 1162b07682b6SSantosh Shilimkar status = -ENOMEM; 1163b07682b6SSantosh Shilimkar goto fail; 1164b07682b6SSantosh Shilimkar } 1165b07682b6SSantosh Shilimkar } 11662473d25aSPeter Ujfalusi 11672473d25aSPeter Ujfalusi twl->regmap = devm_regmap_init_i2c(twl->client, 11682473d25aSPeter Ujfalusi &twl_regmap_config[i]); 11692473d25aSPeter Ujfalusi if (IS_ERR(twl->regmap)) { 11702473d25aSPeter Ujfalusi status = PTR_ERR(twl->regmap); 11712473d25aSPeter Ujfalusi dev_err(&client->dev, 11722473d25aSPeter Ujfalusi "Failed to allocate regmap %d, err: %d\n", i, 11732473d25aSPeter Ujfalusi status); 11742473d25aSPeter Ujfalusi goto fail; 11752473d25aSPeter Ujfalusi } 1176b07682b6SSantosh Shilimkar } 1177ec1a07b3SBenoit Cousson 117880a97ccdSPeter Ujfalusi twl_priv->ready = true; 1179b07682b6SSantosh Shilimkar 1180b07682b6SSantosh Shilimkar /* setup clock framework */ 11817e2e6c57SPeter Ujfalusi clocks_init(&pdev->dev, pdata ? pdata->clock : NULL); 1182b07682b6SSantosh Shilimkar 1183ca972d13SLesly A M /* read TWL IDCODE Register */ 118480a97ccdSPeter Ujfalusi if (twl_class_is_4030()) { 1185ec1a07b3SBenoit Cousson status = twl_read_idcode_register(); 1186ec1a07b3SBenoit Cousson WARN(status < 0, "Error: reading twl_idcode register value\n"); 1187ca972d13SLesly A M } 1188ca972d13SLesly A M 1189b07682b6SSantosh Shilimkar /* Maybe init the T2 Interrupt subsystem */ 11909e178620SFelipe Balbi if (client->irq) { 1191e8deb28cSBalaji T K if (twl_class_is_4030()) { 1192e8deb28cSBalaji T K twl4030_init_chip_irq(id->name); 119378518ffaSBenoit Cousson irq_base = twl4030_init_irq(&client->dev, client->irq); 1194e8deb28cSBalaji T K } else { 119578518ffaSBenoit Cousson irq_base = twl6030_init_irq(&client->dev, client->irq); 1196e8deb28cSBalaji T K } 1197e8deb28cSBalaji T K 119878518ffaSBenoit Cousson if (irq_base < 0) { 119978518ffaSBenoit Cousson status = irq_base; 1200b07682b6SSantosh Shilimkar goto fail; 1201b07682b6SSantosh Shilimkar } 120278518ffaSBenoit Cousson } 1203b07682b6SSantosh Shilimkar 1204ec1a07b3SBenoit Cousson /* 1205ec1a07b3SBenoit Cousson * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. 1206a29aaf55SMoiz Sonasath * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, 1207a29aaf55SMoiz Sonasath * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. 1208a613b739STony Lindgren * 1209a613b739STony Lindgren * Also, always enable SmartReflex bit as that's needed for omaps to 1210a613b739STony Lindgren * to do anything over I2C4 for voltage scaling even if SmartReflex 1211a613b739STony Lindgren * is disabled. Without the SmartReflex bit omap sys_clkreq idle 1212a613b739STony Lindgren * signal will never trigger for retention idle. 1213a29aaf55SMoiz Sonasath */ 1214a29aaf55SMoiz Sonasath if (twl_class_is_4030()) { 1215ec1a07b3SBenoit Cousson u8 temp; 1216ec1a07b3SBenoit Cousson 1217a29aaf55SMoiz Sonasath twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1); 1218a29aaf55SMoiz Sonasath temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ 1219a29aaf55SMoiz Sonasath I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); 1220a29aaf55SMoiz Sonasath twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); 1221a613b739STony Lindgren 1222a613b739STony Lindgren twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, 1223a613b739STony Lindgren TWL4030_DCDC_GLOBAL_CFG); 1224a613b739STony Lindgren temp |= SMARTREFLEX_ENABLE; 1225a613b739STony Lindgren twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, 1226a613b739STony Lindgren TWL4030_DCDC_GLOBAL_CFG); 1227a29aaf55SMoiz Sonasath } 1228a29aaf55SMoiz Sonasath 122980ec831eSTony Lindgren if (node) { 123080ec831eSTony Lindgren if (pdata) 123180ec831eSTony Lindgren twl_auxdata_lookup[0].platform_data = pdata->gpio; 123280ec831eSTony Lindgren status = of_platform_populate(node, NULL, twl_auxdata_lookup, 123380ec831eSTony Lindgren &client->dev); 123480ec831eSTony Lindgren } else { 12359e178620SFelipe Balbi status = add_children(pdata, irq_base, id->driver_data); 123680ec831eSTony Lindgren } 1237aeb5032bSBenoit Cousson 1238b07682b6SSantosh Shilimkar fail: 1239b07682b6SSantosh Shilimkar if (status < 0) 1240fc7b92fcSBalaji T K twl_remove(client); 1241defa6be1STony Lindgren free: 1242defa6be1STony Lindgren if (status < 0) 1243defa6be1STony Lindgren platform_device_unregister(pdev); 1244ec1a07b3SBenoit Cousson 1245b07682b6SSantosh Shilimkar return status; 1246b07682b6SSantosh Shilimkar } 1247b07682b6SSantosh Shilimkar 1248fc7b92fcSBalaji T K static const struct i2c_device_id twl_ids[] = { 1249b07682b6SSantosh Shilimkar { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ 1250b07682b6SSantosh Shilimkar { "twl5030", 0 }, /* T2 updated */ 1251b07682b6SSantosh Shilimkar { "twl5031", TWL5031 }, /* TWL5030 updated */ 1252b07682b6SSantosh Shilimkar { "tps65950", 0 }, /* catalog version of twl5030 */ 1253b07682b6SSantosh Shilimkar { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ 1254b07682b6SSantosh Shilimkar { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ 125559dead5aSOleg Drokin { "tps65921", TPS_SUBSET }, /* fewer LDOs; no codec, no LED 125659dead5aSOleg Drokin and vibrator. Charger in USB module*/ 1257e8deb28cSBalaji T K { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ 125889ce43fbSGraeme Gregory { "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */ 1259b07682b6SSantosh Shilimkar { /* end of list */ }, 1260b07682b6SSantosh Shilimkar }; 1261fc7b92fcSBalaji T K MODULE_DEVICE_TABLE(i2c, twl_ids); 1262b07682b6SSantosh Shilimkar 1263b07682b6SSantosh Shilimkar /* One Client Driver , 4 Clients */ 1264fc7b92fcSBalaji T K static struct i2c_driver twl_driver = { 1265b07682b6SSantosh Shilimkar .driver.name = DRIVER_NAME, 1266fc7b92fcSBalaji T K .id_table = twl_ids, 1267fc7b92fcSBalaji T K .probe = twl_probe, 1268fc7b92fcSBalaji T K .remove = twl_remove, 1269b07682b6SSantosh Shilimkar }; 1270b07682b6SSantosh Shilimkar 1271032fa16dSGrygorii Strashko module_i2c_driver(twl_driver); 1272b07682b6SSantosh Shilimkar 1273b07682b6SSantosh Shilimkar MODULE_AUTHOR("Texas Instruments, Inc."); 1274fc7b92fcSBalaji T K MODULE_DESCRIPTION("I2C Core interface for TWL"); 1275b07682b6SSantosh Shilimkar MODULE_LICENSE("GPL"); 1276