162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM 462306a36Sopenharmony_ci * and audio CODEC devices 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2005-2006 Texas Instruments, Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Modifications to defer interrupt handling to a kernel thread: 962306a36Sopenharmony_ci * Copyright (C) 2006 MontaVista Software, Inc. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Based on tlv320aic23.c: 1262306a36Sopenharmony_ci * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Code cleanup and modifications to IRQ handler. 1562306a36Sopenharmony_ci * by syed khasim <x0khasim@ti.com> 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/regmap.h> 2262306a36Sopenharmony_ci#include <linux/clk.h> 2362306a36Sopenharmony_ci#include <linux/err.h> 2462306a36Sopenharmony_ci#include <linux/device.h> 2562306a36Sopenharmony_ci#include <linux/of.h> 2662306a36Sopenharmony_ci#include <linux/of_irq.h> 2762306a36Sopenharmony_ci#include <linux/of_platform.h> 2862306a36Sopenharmony_ci#include <linux/irq.h> 2962306a36Sopenharmony_ci#include <linux/irqdomain.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/regulator/machine.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/i2c.h> 3462306a36Sopenharmony_ci#include <linux/mfd/twl.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Register descriptions for audio */ 3762306a36Sopenharmony_ci#include <linux/mfd/twl4030-audio.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "twl-core.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * The TWL4030 "Triton 2" is one of a family of a multi-function "Power 4362306a36Sopenharmony_ci * Management and System Companion Device" chips originally designed for 4462306a36Sopenharmony_ci * use in OMAP2 and OMAP 3 based systems. Its control interfaces use I2C, 4562306a36Sopenharmony_ci * often at around 3 Mbit/sec, including for interrupt handling. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * This driver core provides genirq support for the interrupts emitted, 4862306a36Sopenharmony_ci * by the various modules, and exports register access primitives. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * FIXME this driver currently requires use of the first interrupt line 5162306a36Sopenharmony_ci * (and associated registers). 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define DRIVER_NAME "twl" 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* Triton Core internal information (BEGIN) */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Base Address defns for twl4030_map[] */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* subchip/slave 0 - USB ID */ 6162306a36Sopenharmony_ci#define TWL4030_BASEADD_USB 0x0000 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* subchip/slave 1 - AUD ID */ 6462306a36Sopenharmony_ci#define TWL4030_BASEADD_AUDIO_VOICE 0x0000 6562306a36Sopenharmony_ci#define TWL4030_BASEADD_GPIO 0x0098 6662306a36Sopenharmony_ci#define TWL4030_BASEADD_INTBR 0x0085 6762306a36Sopenharmony_ci#define TWL4030_BASEADD_PIH 0x0080 6862306a36Sopenharmony_ci#define TWL4030_BASEADD_TEST 0x004C 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* subchip/slave 2 - AUX ID */ 7162306a36Sopenharmony_ci#define TWL4030_BASEADD_INTERRUPTS 0x00B9 7262306a36Sopenharmony_ci#define TWL4030_BASEADD_LED 0x00EE 7362306a36Sopenharmony_ci#define TWL4030_BASEADD_MADC 0x0000 7462306a36Sopenharmony_ci#define TWL4030_BASEADD_MAIN_CHARGE 0x0074 7562306a36Sopenharmony_ci#define TWL4030_BASEADD_PRECHARGE 0x00AA 7662306a36Sopenharmony_ci#define TWL4030_BASEADD_PWM 0x00F8 7762306a36Sopenharmony_ci#define TWL4030_BASEADD_KEYPAD 0x00D2 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */ 8062306a36Sopenharmony_ci#define TWL5031_BASEADD_INTERRUPTS 0x00B9 /* Different than TWL4030's 8162306a36Sopenharmony_ci one */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* subchip/slave 3 - POWER ID */ 8462306a36Sopenharmony_ci#define TWL4030_BASEADD_BACKUP 0x0014 8562306a36Sopenharmony_ci#define TWL4030_BASEADD_INT 0x002E 8662306a36Sopenharmony_ci#define TWL4030_BASEADD_PM_MASTER 0x0036 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define TWL4030_BASEADD_PM_RECEIVER 0x005B 8962306a36Sopenharmony_ci#define TWL4030_DCDC_GLOBAL_CFG 0x06 9062306a36Sopenharmony_ci#define SMARTREFLEX_ENABLE BIT(3) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define TWL4030_BASEADD_RTC 0x001C 9362306a36Sopenharmony_ci#define TWL4030_BASEADD_SECURED_REG 0x0000 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Triton Core internal information (END) */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* subchip/slave 0 0x48 - POWER */ 9962306a36Sopenharmony_ci#define TWL6030_BASEADD_RTC 0x0000 10062306a36Sopenharmony_ci#define TWL6030_BASEADD_SECURED_REG 0x0017 10162306a36Sopenharmony_ci#define TWL6030_BASEADD_PM_MASTER 0x001F 10262306a36Sopenharmony_ci#define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ 10362306a36Sopenharmony_ci#define TWL6030_BASEADD_PM_MISC 0x00E2 10462306a36Sopenharmony_ci#define TWL6030_BASEADD_PM_PUPD 0x00F0 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* subchip/slave 1 0x49 - FEATURE */ 10762306a36Sopenharmony_ci#define TWL6030_BASEADD_USB 0x0000 10862306a36Sopenharmony_ci#define TWL6030_BASEADD_GPADC_CTRL 0x002E 10962306a36Sopenharmony_ci#define TWL6030_BASEADD_AUX 0x0090 11062306a36Sopenharmony_ci#define TWL6030_BASEADD_PWM 0x00BA 11162306a36Sopenharmony_ci#define TWL6030_BASEADD_GASGAUGE 0x00C0 11262306a36Sopenharmony_ci#define TWL6030_BASEADD_PIH 0x00D0 11362306a36Sopenharmony_ci#define TWL6032_BASEADD_CHARGER 0x00DA 11462306a36Sopenharmony_ci#define TWL6030_BASEADD_CHARGER 0x00E0 11562306a36Sopenharmony_ci#define TWL6030_BASEADD_LED 0x00F4 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* subchip/slave 2 0x4A - DFT */ 11862306a36Sopenharmony_ci#define TWL6030_BASEADD_DIEID 0x00C0 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* subchip/slave 3 0x4B - AUDIO */ 12162306a36Sopenharmony_ci#define TWL6030_BASEADD_AUDIO 0x0000 12262306a36Sopenharmony_ci#define TWL6030_BASEADD_RSV 0x0000 12362306a36Sopenharmony_ci#define TWL6030_BASEADD_ZERO 0x0000 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Few power values */ 12662306a36Sopenharmony_ci#define R_CFG_BOOT 0x05 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* some fields in R_CFG_BOOT */ 12962306a36Sopenharmony_ci#define HFCLK_FREQ_19p2_MHZ (1 << 0) 13062306a36Sopenharmony_ci#define HFCLK_FREQ_26_MHZ (2 << 0) 13162306a36Sopenharmony_ci#define HFCLK_FREQ_38p4_MHZ (3 << 0) 13262306a36Sopenharmony_ci#define HIGH_PERF_SQ (1 << 3) 13362306a36Sopenharmony_ci#define CK32K_LOWPWR_EN (1 << 7) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* Structure for each TWL4030/TWL6030 Slave */ 13862306a36Sopenharmony_cistruct twl_client { 13962306a36Sopenharmony_ci struct i2c_client *client; 14062306a36Sopenharmony_ci struct regmap *regmap; 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* mapping the module id to slave id and base address */ 14462306a36Sopenharmony_cistruct twl_mapping { 14562306a36Sopenharmony_ci unsigned char sid; /* Slave ID */ 14662306a36Sopenharmony_ci unsigned char base; /* base address */ 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistruct twl_private { 15062306a36Sopenharmony_ci bool ready; /* The core driver is ready to be used */ 15162306a36Sopenharmony_ci u32 twl_idcode; /* TWL IDCODE Register value */ 15262306a36Sopenharmony_ci unsigned int twl_id; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci struct twl_mapping *twl_map; 15562306a36Sopenharmony_ci struct twl_client *twl_modules; 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct twl_private *twl_priv; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic struct twl_mapping twl4030_map[] = { 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * NOTE: don't change this table without updating the 16362306a36Sopenharmony_ci * <linux/mfd/twl.h> defines for TWL4030_MODULE_* 16462306a36Sopenharmony_ci * so they continue to match the order in this table. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Common IPs */ 16862306a36Sopenharmony_ci { 0, TWL4030_BASEADD_USB }, 16962306a36Sopenharmony_ci { 1, TWL4030_BASEADD_PIH }, 17062306a36Sopenharmony_ci { 2, TWL4030_BASEADD_MAIN_CHARGE }, 17162306a36Sopenharmony_ci { 3, TWL4030_BASEADD_PM_MASTER }, 17262306a36Sopenharmony_ci { 3, TWL4030_BASEADD_PM_RECEIVER }, 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci { 3, TWL4030_BASEADD_RTC }, 17562306a36Sopenharmony_ci { 2, TWL4030_BASEADD_PWM }, 17662306a36Sopenharmony_ci { 2, TWL4030_BASEADD_LED }, 17762306a36Sopenharmony_ci { 3, TWL4030_BASEADD_SECURED_REG }, 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* TWL4030 specific IPs */ 18062306a36Sopenharmony_ci { 1, TWL4030_BASEADD_AUDIO_VOICE }, 18162306a36Sopenharmony_ci { 1, TWL4030_BASEADD_GPIO }, 18262306a36Sopenharmony_ci { 1, TWL4030_BASEADD_INTBR }, 18362306a36Sopenharmony_ci { 1, TWL4030_BASEADD_TEST }, 18462306a36Sopenharmony_ci { 2, TWL4030_BASEADD_KEYPAD }, 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci { 2, TWL4030_BASEADD_MADC }, 18762306a36Sopenharmony_ci { 2, TWL4030_BASEADD_INTERRUPTS }, 18862306a36Sopenharmony_ci { 2, TWL4030_BASEADD_PRECHARGE }, 18962306a36Sopenharmony_ci { 3, TWL4030_BASEADD_BACKUP }, 19062306a36Sopenharmony_ci { 3, TWL4030_BASEADD_INT }, 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci { 2, TWL5031_BASEADD_ACCESSORY }, 19362306a36Sopenharmony_ci { 2, TWL5031_BASEADD_INTERRUPTS }, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic const struct reg_default twl4030_49_defaults[] = { 19762306a36Sopenharmony_ci /* Audio Registers */ 19862306a36Sopenharmony_ci { 0x01, 0x00}, /* CODEC_MODE */ 19962306a36Sopenharmony_ci { 0x02, 0x00}, /* OPTION */ 20062306a36Sopenharmony_ci /* 0x03 Unused */ 20162306a36Sopenharmony_ci { 0x04, 0x00}, /* MICBIAS_CTL */ 20262306a36Sopenharmony_ci { 0x05, 0x00}, /* ANAMICL */ 20362306a36Sopenharmony_ci { 0x06, 0x00}, /* ANAMICR */ 20462306a36Sopenharmony_ci { 0x07, 0x00}, /* AVADC_CTL */ 20562306a36Sopenharmony_ci { 0x08, 0x00}, /* ADCMICSEL */ 20662306a36Sopenharmony_ci { 0x09, 0x00}, /* DIGMIXING */ 20762306a36Sopenharmony_ci { 0x0a, 0x0f}, /* ATXL1PGA */ 20862306a36Sopenharmony_ci { 0x0b, 0x0f}, /* ATXR1PGA */ 20962306a36Sopenharmony_ci { 0x0c, 0x0f}, /* AVTXL2PGA */ 21062306a36Sopenharmony_ci { 0x0d, 0x0f}, /* AVTXR2PGA */ 21162306a36Sopenharmony_ci { 0x0e, 0x00}, /* AUDIO_IF */ 21262306a36Sopenharmony_ci { 0x0f, 0x00}, /* VOICE_IF */ 21362306a36Sopenharmony_ci { 0x10, 0x3f}, /* ARXR1PGA */ 21462306a36Sopenharmony_ci { 0x11, 0x3f}, /* ARXL1PGA */ 21562306a36Sopenharmony_ci { 0x12, 0x3f}, /* ARXR2PGA */ 21662306a36Sopenharmony_ci { 0x13, 0x3f}, /* ARXL2PGA */ 21762306a36Sopenharmony_ci { 0x14, 0x25}, /* VRXPGA */ 21862306a36Sopenharmony_ci { 0x15, 0x00}, /* VSTPGA */ 21962306a36Sopenharmony_ci { 0x16, 0x00}, /* VRX2ARXPGA */ 22062306a36Sopenharmony_ci { 0x17, 0x00}, /* AVDAC_CTL */ 22162306a36Sopenharmony_ci { 0x18, 0x00}, /* ARX2VTXPGA */ 22262306a36Sopenharmony_ci { 0x19, 0x32}, /* ARXL1_APGA_CTL*/ 22362306a36Sopenharmony_ci { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/ 22462306a36Sopenharmony_ci { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/ 22562306a36Sopenharmony_ci { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/ 22662306a36Sopenharmony_ci { 0x1d, 0x00}, /* ATX2ARXPGA */ 22762306a36Sopenharmony_ci { 0x1e, 0x00}, /* BT_IF */ 22862306a36Sopenharmony_ci { 0x1f, 0x55}, /* BTPGA */ 22962306a36Sopenharmony_ci { 0x20, 0x00}, /* BTSTPGA */ 23062306a36Sopenharmony_ci { 0x21, 0x00}, /* EAR_CTL */ 23162306a36Sopenharmony_ci { 0x22, 0x00}, /* HS_SEL */ 23262306a36Sopenharmony_ci { 0x23, 0x00}, /* HS_GAIN_SET */ 23362306a36Sopenharmony_ci { 0x24, 0x00}, /* HS_POPN_SET */ 23462306a36Sopenharmony_ci { 0x25, 0x00}, /* PREDL_CTL */ 23562306a36Sopenharmony_ci { 0x26, 0x00}, /* PREDR_CTL */ 23662306a36Sopenharmony_ci { 0x27, 0x00}, /* PRECKL_CTL */ 23762306a36Sopenharmony_ci { 0x28, 0x00}, /* PRECKR_CTL */ 23862306a36Sopenharmony_ci { 0x29, 0x00}, /* HFL_CTL */ 23962306a36Sopenharmony_ci { 0x2a, 0x00}, /* HFR_CTL */ 24062306a36Sopenharmony_ci { 0x2b, 0x05}, /* ALC_CTL */ 24162306a36Sopenharmony_ci { 0x2c, 0x00}, /* ALC_SET1 */ 24262306a36Sopenharmony_ci { 0x2d, 0x00}, /* ALC_SET2 */ 24362306a36Sopenharmony_ci { 0x2e, 0x00}, /* BOOST_CTL */ 24462306a36Sopenharmony_ci { 0x2f, 0x00}, /* SOFTVOL_CTL */ 24562306a36Sopenharmony_ci { 0x30, 0x13}, /* DTMF_FREQSEL */ 24662306a36Sopenharmony_ci { 0x31, 0x00}, /* DTMF_TONEXT1H */ 24762306a36Sopenharmony_ci { 0x32, 0x00}, /* DTMF_TONEXT1L */ 24862306a36Sopenharmony_ci { 0x33, 0x00}, /* DTMF_TONEXT2H */ 24962306a36Sopenharmony_ci { 0x34, 0x00}, /* DTMF_TONEXT2L */ 25062306a36Sopenharmony_ci { 0x35, 0x79}, /* DTMF_TONOFF */ 25162306a36Sopenharmony_ci { 0x36, 0x11}, /* DTMF_WANONOFF */ 25262306a36Sopenharmony_ci { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */ 25362306a36Sopenharmony_ci { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */ 25462306a36Sopenharmony_ci { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */ 25562306a36Sopenharmony_ci { 0x3a, 0x06}, /* APLL_CTL */ 25662306a36Sopenharmony_ci { 0x3b, 0x00}, /* DTMF_CTL */ 25762306a36Sopenharmony_ci { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */ 25862306a36Sopenharmony_ci { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */ 25962306a36Sopenharmony_ci { 0x3e, 0x00}, /* MISC_SET_1 */ 26062306a36Sopenharmony_ci { 0x3f, 0x00}, /* PCMBTMUX */ 26162306a36Sopenharmony_ci /* 0x40 - 0x42 Unused */ 26262306a36Sopenharmony_ci { 0x43, 0x00}, /* RX_PATH_SEL */ 26362306a36Sopenharmony_ci { 0x44, 0x32}, /* VDL_APGA_CTL */ 26462306a36Sopenharmony_ci { 0x45, 0x00}, /* VIBRA_CTL */ 26562306a36Sopenharmony_ci { 0x46, 0x00}, /* VIBRA_SET */ 26662306a36Sopenharmony_ci { 0x47, 0x00}, /* VIBRA_PWM_SET */ 26762306a36Sopenharmony_ci { 0x48, 0x00}, /* ANAMIC_GAIN */ 26862306a36Sopenharmony_ci { 0x49, 0x00}, /* MISC_SET_2 */ 26962306a36Sopenharmony_ci /* End of Audio Registers */ 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic bool twl4030_49_nop_reg(struct device *dev, unsigned int reg) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci switch (reg) { 27562306a36Sopenharmony_ci case 0x00: 27662306a36Sopenharmony_ci case 0x03: 27762306a36Sopenharmony_ci case 0x40: 27862306a36Sopenharmony_ci case 0x41: 27962306a36Sopenharmony_ci case 0x42: 28062306a36Sopenharmony_ci return false; 28162306a36Sopenharmony_ci default: 28262306a36Sopenharmony_ci return true; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic const struct regmap_range twl4030_49_volatile_ranges[] = { 28762306a36Sopenharmony_ci regmap_reg_range(TWL4030_BASEADD_TEST, 0xff), 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic const struct regmap_access_table twl4030_49_volatile_table = { 29162306a36Sopenharmony_ci .yes_ranges = twl4030_49_volatile_ranges, 29262306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges), 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic const struct regmap_config twl4030_regmap_config[4] = { 29662306a36Sopenharmony_ci { 29762306a36Sopenharmony_ci /* Address 0x48 */ 29862306a36Sopenharmony_ci .reg_bits = 8, 29962306a36Sopenharmony_ci .val_bits = 8, 30062306a36Sopenharmony_ci .max_register = 0xff, 30162306a36Sopenharmony_ci }, 30262306a36Sopenharmony_ci { 30362306a36Sopenharmony_ci /* Address 0x49 */ 30462306a36Sopenharmony_ci .reg_bits = 8, 30562306a36Sopenharmony_ci .val_bits = 8, 30662306a36Sopenharmony_ci .max_register = 0xff, 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci .readable_reg = twl4030_49_nop_reg, 30962306a36Sopenharmony_ci .writeable_reg = twl4030_49_nop_reg, 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci .volatile_table = &twl4030_49_volatile_table, 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci .reg_defaults = twl4030_49_defaults, 31462306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), 31562306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 31662306a36Sopenharmony_ci }, 31762306a36Sopenharmony_ci { 31862306a36Sopenharmony_ci /* Address 0x4a */ 31962306a36Sopenharmony_ci .reg_bits = 8, 32062306a36Sopenharmony_ci .val_bits = 8, 32162306a36Sopenharmony_ci .max_register = 0xff, 32262306a36Sopenharmony_ci }, 32362306a36Sopenharmony_ci { 32462306a36Sopenharmony_ci /* Address 0x4b */ 32562306a36Sopenharmony_ci .reg_bits = 8, 32662306a36Sopenharmony_ci .val_bits = 8, 32762306a36Sopenharmony_ci .max_register = 0xff, 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci}; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic struct twl_mapping twl6030_map[] = { 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * NOTE: don't change this table without updating the 33462306a36Sopenharmony_ci * <linux/mfd/twl.h> defines for TWL4030_MODULE_* 33562306a36Sopenharmony_ci * so they continue to match the order in this table. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Common IPs */ 33962306a36Sopenharmony_ci { 1, TWL6030_BASEADD_USB }, 34062306a36Sopenharmony_ci { 1, TWL6030_BASEADD_PIH }, 34162306a36Sopenharmony_ci { 1, TWL6030_BASEADD_CHARGER }, 34262306a36Sopenharmony_ci { 0, TWL6030_BASEADD_PM_MASTER }, 34362306a36Sopenharmony_ci { 0, TWL6030_BASEADD_PM_SLAVE_MISC }, 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci { 0, TWL6030_BASEADD_RTC }, 34662306a36Sopenharmony_ci { 1, TWL6030_BASEADD_PWM }, 34762306a36Sopenharmony_ci { 1, TWL6030_BASEADD_LED }, 34862306a36Sopenharmony_ci { 0, TWL6030_BASEADD_SECURED_REG }, 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* TWL6030 specific IPs */ 35162306a36Sopenharmony_ci { 0, TWL6030_BASEADD_ZERO }, 35262306a36Sopenharmony_ci { 1, TWL6030_BASEADD_ZERO }, 35362306a36Sopenharmony_ci { 2, TWL6030_BASEADD_ZERO }, 35462306a36Sopenharmony_ci { 1, TWL6030_BASEADD_GPADC_CTRL }, 35562306a36Sopenharmony_ci { 1, TWL6030_BASEADD_GASGAUGE }, 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* TWL6032 specific charger registers */ 35862306a36Sopenharmony_ci { 1, TWL6032_BASEADD_CHARGER }, 35962306a36Sopenharmony_ci}; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic const struct regmap_config twl6030_regmap_config[3] = { 36262306a36Sopenharmony_ci { 36362306a36Sopenharmony_ci /* Address 0x48 */ 36462306a36Sopenharmony_ci .reg_bits = 8, 36562306a36Sopenharmony_ci .val_bits = 8, 36662306a36Sopenharmony_ci .max_register = 0xff, 36762306a36Sopenharmony_ci }, 36862306a36Sopenharmony_ci { 36962306a36Sopenharmony_ci /* Address 0x49 */ 37062306a36Sopenharmony_ci .reg_bits = 8, 37162306a36Sopenharmony_ci .val_bits = 8, 37262306a36Sopenharmony_ci .max_register = 0xff, 37362306a36Sopenharmony_ci }, 37462306a36Sopenharmony_ci { 37562306a36Sopenharmony_ci /* Address 0x4a */ 37662306a36Sopenharmony_ci .reg_bits = 8, 37762306a36Sopenharmony_ci .val_bits = 8, 37862306a36Sopenharmony_ci .max_register = 0xff, 37962306a36Sopenharmony_ci }, 38062306a36Sopenharmony_ci}; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic inline int twl_get_num_slaves(void) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci if (twl_class_is_4030()) 38762306a36Sopenharmony_ci return 4; /* TWL4030 class have four slave address */ 38862306a36Sopenharmony_ci else 38962306a36Sopenharmony_ci return 3; /* TWL6030 class have three slave address */ 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic inline int twl_get_last_module(void) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci if (twl_class_is_4030()) 39562306a36Sopenharmony_ci return TWL4030_MODULE_LAST; 39662306a36Sopenharmony_ci else 39762306a36Sopenharmony_ci return TWL6030_MODULE_LAST; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* Exported Functions */ 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciunsigned int twl_rev(void) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci return twl_priv ? twl_priv->twl_id : 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ciEXPORT_SYMBOL(twl_rev); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/** 40962306a36Sopenharmony_ci * twl_get_regmap - Get the regmap associated with the given module 41062306a36Sopenharmony_ci * @mod_no: module number 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Returns the regmap pointer or NULL in case of failure. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_cistatic struct regmap *twl_get_regmap(u8 mod_no) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci int sid; 41762306a36Sopenharmony_ci struct twl_client *twl; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (unlikely(!twl_priv || !twl_priv->ready)) { 42062306a36Sopenharmony_ci pr_err("%s: not initialized\n", DRIVER_NAME); 42162306a36Sopenharmony_ci return NULL; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci if (unlikely(mod_no >= twl_get_last_module())) { 42462306a36Sopenharmony_ci pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); 42562306a36Sopenharmony_ci return NULL; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci sid = twl_priv->twl_map[mod_no].sid; 42962306a36Sopenharmony_ci twl = &twl_priv->twl_modules[sid]; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return twl->regmap; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/** 43562306a36Sopenharmony_ci * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 43662306a36Sopenharmony_ci * @mod_no: module number 43762306a36Sopenharmony_ci * @value: an array of num_bytes+1 containing data to write 43862306a36Sopenharmony_ci * @reg: register address (just offset will do) 43962306a36Sopenharmony_ci * @num_bytes: number of bytes to transfer 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * Returns 0 on success or else a negative error code. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ciint twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct regmap *regmap = twl_get_regmap(mod_no); 44662306a36Sopenharmony_ci int ret; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (!regmap) 44962306a36Sopenharmony_ci return -EPERM; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg, 45262306a36Sopenharmony_ci value, num_bytes); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (ret) 45562306a36Sopenharmony_ci pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", 45662306a36Sopenharmony_ci DRIVER_NAME, mod_no, reg, num_bytes); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return ret; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ciEXPORT_SYMBOL(twl_i2c_write); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/** 46362306a36Sopenharmony_ci * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0 46462306a36Sopenharmony_ci * @mod_no: module number 46562306a36Sopenharmony_ci * @value: an array of num_bytes containing data to be read 46662306a36Sopenharmony_ci * @reg: register address (just offset will do) 46762306a36Sopenharmony_ci * @num_bytes: number of bytes to transfer 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * Returns 0 on success or else a negative error code. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ciint twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct regmap *regmap = twl_get_regmap(mod_no); 47462306a36Sopenharmony_ci int ret; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!regmap) 47762306a36Sopenharmony_ci return -EPERM; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg, 48062306a36Sopenharmony_ci value, num_bytes); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (ret) 48362306a36Sopenharmony_ci pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n", 48462306a36Sopenharmony_ci DRIVER_NAME, mod_no, reg, num_bytes); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ciEXPORT_SYMBOL(twl_i2c_read); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/** 49162306a36Sopenharmony_ci * twl_set_regcache_bypass - Configure the regcache bypass for the regmap associated 49262306a36Sopenharmony_ci * with the module 49362306a36Sopenharmony_ci * @mod_no: module number 49462306a36Sopenharmony_ci * @enable: Regcache bypass state 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * Returns 0 else failure. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ciint twl_set_regcache_bypass(u8 mod_no, bool enable) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct regmap *regmap = twl_get_regmap(mod_no); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (!regmap) 50362306a36Sopenharmony_ci return -EPERM; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci regcache_cache_bypass(regmap, enable); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ciEXPORT_SYMBOL(twl_set_regcache_bypass); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/** 51462306a36Sopenharmony_ci * twl_read_idcode_register - API to read the IDCODE register. 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * Unlocks the IDCODE register and read the 32 bit value. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cistatic int twl_read_idcode_register(void) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci int err; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK, 52362306a36Sopenharmony_ci REG_UNLOCK_TEST_REG); 52462306a36Sopenharmony_ci if (err) { 52562306a36Sopenharmony_ci pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err); 52662306a36Sopenharmony_ci goto fail; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode), 53062306a36Sopenharmony_ci REG_IDCODE_7_0, 4); 53162306a36Sopenharmony_ci if (err) { 53262306a36Sopenharmony_ci pr_err("TWL4030: unable to read IDCODE -%d\n", err); 53362306a36Sopenharmony_ci goto fail; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG); 53762306a36Sopenharmony_ci if (err) 53862306a36Sopenharmony_ci pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err); 53962306a36Sopenharmony_cifail: 54062306a36Sopenharmony_ci return err; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/** 54462306a36Sopenharmony_ci * twl_get_type - API to get TWL Si type. 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * Api to get the TWL Si type from IDCODE value. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ciint twl_get_type(void) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci return TWL_SIL_TYPE(twl_priv->twl_idcode); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(twl_get_type); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci/** 55562306a36Sopenharmony_ci * twl_get_version - API to get TWL Si version. 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * Api to get the TWL Si version from IDCODE value. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ciint twl_get_version(void) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci return TWL_SIL_REV(twl_priv->twl_idcode); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(twl_get_version); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/** 56662306a36Sopenharmony_ci * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. 56762306a36Sopenharmony_ci * 56862306a36Sopenharmony_ci * Api to get the TWL HFCLK rate based on BOOT_CFG register. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ciint twl_get_hfclk_rate(void) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci u8 ctrl; 57362306a36Sopenharmony_ci int rate; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci switch (ctrl & 0x3) { 57862306a36Sopenharmony_ci case HFCLK_FREQ_19p2_MHZ: 57962306a36Sopenharmony_ci rate = 19200000; 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci case HFCLK_FREQ_26_MHZ: 58262306a36Sopenharmony_ci rate = 26000000; 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case HFCLK_FREQ_38p4_MHZ: 58562306a36Sopenharmony_ci rate = 38400000; 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci default: 58862306a36Sopenharmony_ci pr_err("TWL4030: HFCLK is not configured\n"); 58962306a36Sopenharmony_ci rate = -EINVAL; 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return rate; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(twl_get_hfclk_rate); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* 60062306a36Sopenharmony_ci * These three functions initialize the on-chip clock framework, 60162306a36Sopenharmony_ci * letting it generate the right frequencies for USB, MADC, and 60262306a36Sopenharmony_ci * other purposes. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_cistatic inline int protect_pm_master(void) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci int e = 0; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, 60962306a36Sopenharmony_ci TWL4030_PM_MASTER_PROTECT_KEY); 61062306a36Sopenharmony_ci return e; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic inline int unprotect_pm_master(void) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci int e = 0; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, 61862306a36Sopenharmony_ci TWL4030_PM_MASTER_PROTECT_KEY); 61962306a36Sopenharmony_ci e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, 62062306a36Sopenharmony_ci TWL4030_PM_MASTER_PROTECT_KEY); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return e; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void clocks_init(struct device *dev) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci int e = 0; 62862306a36Sopenharmony_ci struct clk *osc; 62962306a36Sopenharmony_ci u32 rate; 63062306a36Sopenharmony_ci u8 ctrl = HFCLK_FREQ_26_MHZ; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci osc = clk_get(dev, "fck"); 63362306a36Sopenharmony_ci if (IS_ERR(osc)) { 63462306a36Sopenharmony_ci printk(KERN_WARNING "Skipping twl internal clock init and " 63562306a36Sopenharmony_ci "using bootloader value (unknown osc rate)\n"); 63662306a36Sopenharmony_ci return; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci rate = clk_get_rate(osc); 64062306a36Sopenharmony_ci clk_put(osc); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci switch (rate) { 64362306a36Sopenharmony_ci case 19200000: 64462306a36Sopenharmony_ci ctrl = HFCLK_FREQ_19p2_MHZ; 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci case 26000000: 64762306a36Sopenharmony_ci ctrl = HFCLK_FREQ_26_MHZ; 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci case 38400000: 65062306a36Sopenharmony_ci ctrl = HFCLK_FREQ_38p4_MHZ; 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ctrl |= HIGH_PERF_SQ; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci e |= unprotect_pm_master(); 65762306a36Sopenharmony_ci /* effect->MADC+USB ck en */ 65862306a36Sopenharmony_ci e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); 65962306a36Sopenharmony_ci e |= protect_pm_master(); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (e < 0) 66262306a36Sopenharmony_ci pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void twl_remove(struct i2c_client *client) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci unsigned i, num_slaves; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (twl_class_is_4030()) 67362306a36Sopenharmony_ci twl4030_exit_irq(); 67462306a36Sopenharmony_ci else 67562306a36Sopenharmony_ci twl6030_exit_irq(); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci num_slaves = twl_get_num_slaves(); 67862306a36Sopenharmony_ci for (i = 0; i < num_slaves; i++) { 67962306a36Sopenharmony_ci struct twl_client *twl = &twl_priv->twl_modules[i]; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (twl->client && twl->client != client) 68262306a36Sopenharmony_ci i2c_unregister_device(twl->client); 68362306a36Sopenharmony_ci twl->client = NULL; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci twl_priv->ready = false; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic struct of_dev_auxdata twl_auxdata_lookup[] = { 68962306a36Sopenharmony_ci OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), 69062306a36Sopenharmony_ci { /* sentinel */ }, 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/* NOTE: This driver only handles a single twl4030/tps659x0 chip */ 69462306a36Sopenharmony_cistatic int 69562306a36Sopenharmony_citwl_probe(struct i2c_client *client) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 69862306a36Sopenharmony_ci struct device_node *node = client->dev.of_node; 69962306a36Sopenharmony_ci struct platform_device *pdev; 70062306a36Sopenharmony_ci const struct regmap_config *twl_regmap_config; 70162306a36Sopenharmony_ci int irq_base = 0; 70262306a36Sopenharmony_ci int status; 70362306a36Sopenharmony_ci unsigned i, num_slaves; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!node) { 70662306a36Sopenharmony_ci dev_err(&client->dev, "no platform data\n"); 70762306a36Sopenharmony_ci return -EINVAL; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (twl_priv) { 71162306a36Sopenharmony_ci dev_dbg(&client->dev, "only one instance of %s allowed\n", 71262306a36Sopenharmony_ci DRIVER_NAME); 71362306a36Sopenharmony_ci return -EBUSY; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci pdev = platform_device_alloc(DRIVER_NAME, -1); 71762306a36Sopenharmony_ci if (!pdev) { 71862306a36Sopenharmony_ci dev_err(&client->dev, "can't alloc pdev\n"); 71962306a36Sopenharmony_ci return -ENOMEM; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci status = platform_device_add(pdev); 72362306a36Sopenharmony_ci if (status) { 72462306a36Sopenharmony_ci platform_device_put(pdev); 72562306a36Sopenharmony_ci return status; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { 72962306a36Sopenharmony_ci dev_dbg(&client->dev, "can't talk I2C?\n"); 73062306a36Sopenharmony_ci status = -EIO; 73162306a36Sopenharmony_ci goto free; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private), 73562306a36Sopenharmony_ci GFP_KERNEL); 73662306a36Sopenharmony_ci if (!twl_priv) { 73762306a36Sopenharmony_ci status = -ENOMEM; 73862306a36Sopenharmony_ci goto free; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if ((id->driver_data) & TWL6030_CLASS) { 74262306a36Sopenharmony_ci twl_priv->twl_id = TWL6030_CLASS_ID; 74362306a36Sopenharmony_ci twl_priv->twl_map = &twl6030_map[0]; 74462306a36Sopenharmony_ci twl_regmap_config = twl6030_regmap_config; 74562306a36Sopenharmony_ci } else { 74662306a36Sopenharmony_ci twl_priv->twl_id = TWL4030_CLASS_ID; 74762306a36Sopenharmony_ci twl_priv->twl_map = &twl4030_map[0]; 74862306a36Sopenharmony_ci twl_regmap_config = twl4030_regmap_config; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci num_slaves = twl_get_num_slaves(); 75262306a36Sopenharmony_ci twl_priv->twl_modules = devm_kcalloc(&client->dev, 75362306a36Sopenharmony_ci num_slaves, 75462306a36Sopenharmony_ci sizeof(struct twl_client), 75562306a36Sopenharmony_ci GFP_KERNEL); 75662306a36Sopenharmony_ci if (!twl_priv->twl_modules) { 75762306a36Sopenharmony_ci status = -ENOMEM; 75862306a36Sopenharmony_ci goto free; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci for (i = 0; i < num_slaves; i++) { 76262306a36Sopenharmony_ci struct twl_client *twl = &twl_priv->twl_modules[i]; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (i == 0) { 76562306a36Sopenharmony_ci twl->client = client; 76662306a36Sopenharmony_ci } else { 76762306a36Sopenharmony_ci twl->client = i2c_new_dummy_device(client->adapter, 76862306a36Sopenharmony_ci client->addr + i); 76962306a36Sopenharmony_ci if (IS_ERR(twl->client)) { 77062306a36Sopenharmony_ci dev_err(&client->dev, 77162306a36Sopenharmony_ci "can't attach client %d\n", i); 77262306a36Sopenharmony_ci status = PTR_ERR(twl->client); 77362306a36Sopenharmony_ci goto fail; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci twl->regmap = devm_regmap_init_i2c(twl->client, 77862306a36Sopenharmony_ci &twl_regmap_config[i]); 77962306a36Sopenharmony_ci if (IS_ERR(twl->regmap)) { 78062306a36Sopenharmony_ci status = PTR_ERR(twl->regmap); 78162306a36Sopenharmony_ci dev_err(&client->dev, 78262306a36Sopenharmony_ci "Failed to allocate regmap %d, err: %d\n", i, 78362306a36Sopenharmony_ci status); 78462306a36Sopenharmony_ci goto fail; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci twl_priv->ready = true; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* setup clock framework */ 79162306a36Sopenharmony_ci clocks_init(&client->dev); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* read TWL IDCODE Register */ 79462306a36Sopenharmony_ci if (twl_class_is_4030()) { 79562306a36Sopenharmony_ci status = twl_read_idcode_register(); 79662306a36Sopenharmony_ci WARN(status < 0, "Error: reading twl_idcode register value\n"); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Maybe init the T2 Interrupt subsystem */ 80062306a36Sopenharmony_ci if (client->irq) { 80162306a36Sopenharmony_ci if (twl_class_is_4030()) { 80262306a36Sopenharmony_ci twl4030_init_chip_irq(id->name); 80362306a36Sopenharmony_ci irq_base = twl4030_init_irq(&client->dev, client->irq); 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci irq_base = twl6030_init_irq(&client->dev, client->irq); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (irq_base < 0) { 80962306a36Sopenharmony_ci status = irq_base; 81062306a36Sopenharmony_ci goto fail; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* 81562306a36Sopenharmony_ci * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. 81662306a36Sopenharmony_ci * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, 81762306a36Sopenharmony_ci * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. 81862306a36Sopenharmony_ci * 81962306a36Sopenharmony_ci * Also, always enable SmartReflex bit as that's needed for omaps to 82062306a36Sopenharmony_ci * do anything over I2C4 for voltage scaling even if SmartReflex 82162306a36Sopenharmony_ci * is disabled. Without the SmartReflex bit omap sys_clkreq idle 82262306a36Sopenharmony_ci * signal will never trigger for retention idle. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci if (twl_class_is_4030()) { 82562306a36Sopenharmony_ci u8 temp; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1); 82862306a36Sopenharmony_ci temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ 82962306a36Sopenharmony_ci I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); 83062306a36Sopenharmony_ci twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, 83362306a36Sopenharmony_ci TWL4030_DCDC_GLOBAL_CFG); 83462306a36Sopenharmony_ci temp |= SMARTREFLEX_ENABLE; 83562306a36Sopenharmony_ci twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, 83662306a36Sopenharmony_ci TWL4030_DCDC_GLOBAL_CFG); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci status = of_platform_populate(node, NULL, twl_auxdata_lookup, 84062306a36Sopenharmony_ci &client->dev); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cifail: 84362306a36Sopenharmony_ci if (status < 0) 84462306a36Sopenharmony_ci twl_remove(client); 84562306a36Sopenharmony_cifree: 84662306a36Sopenharmony_ci if (status < 0) 84762306a36Sopenharmony_ci platform_device_unregister(pdev); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return status; 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic int __maybe_unused twl_suspend(struct device *dev) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (client->irq) 85762306a36Sopenharmony_ci disable_irq(client->irq); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return 0; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic int __maybe_unused twl_resume(struct device *dev) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (client->irq) 86762306a36Sopenharmony_ci enable_irq(client->irq); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return 0; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(twl_dev_pm_ops, twl_suspend, twl_resume); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic const struct i2c_device_id twl_ids[] = { 87562306a36Sopenharmony_ci { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ 87662306a36Sopenharmony_ci { "twl5030", 0 }, /* T2 updated */ 87762306a36Sopenharmony_ci { "twl5031", TWL5031 }, /* TWL5030 updated */ 87862306a36Sopenharmony_ci { "tps65950", 0 }, /* catalog version of twl5030 */ 87962306a36Sopenharmony_ci { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ 88062306a36Sopenharmony_ci { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ 88162306a36Sopenharmony_ci { "tps65921", TPS_SUBSET }, /* fewer LDOs; no codec, no LED 88262306a36Sopenharmony_ci and vibrator. Charger in USB module*/ 88362306a36Sopenharmony_ci { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ 88462306a36Sopenharmony_ci { "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */ 88562306a36Sopenharmony_ci { /* end of list */ }, 88662306a36Sopenharmony_ci}; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/* One Client Driver , 4 Clients */ 88962306a36Sopenharmony_cistatic struct i2c_driver twl_driver = { 89062306a36Sopenharmony_ci .driver.name = DRIVER_NAME, 89162306a36Sopenharmony_ci .driver.pm = &twl_dev_pm_ops, 89262306a36Sopenharmony_ci .id_table = twl_ids, 89362306a36Sopenharmony_ci .probe = twl_probe, 89462306a36Sopenharmony_ci .remove = twl_remove, 89562306a36Sopenharmony_ci}; 89662306a36Sopenharmony_cibuiltin_i2c_driver(twl_driver); 897