1*88e75cc3SDavid Brownell /* 2*88e75cc3SDavid Brownell * Copyright (C) 2004 Texas Instruments, Inc. 3*88e75cc3SDavid Brownell * 4*88e75cc3SDavid Brownell * Some parts based tps65010.c: 5*88e75cc3SDavid Brownell * Copyright (C) 2004 Texas Instruments and 6*88e75cc3SDavid Brownell * Copyright (C) 2004-2005 David Brownell 7*88e75cc3SDavid Brownell * 8*88e75cc3SDavid Brownell * Some parts based on tlv320aic24.c: 9*88e75cc3SDavid Brownell * Copyright (C) by Kai Svahn <kai.svahn@nokia.com> 10*88e75cc3SDavid Brownell * 11*88e75cc3SDavid Brownell * Changes for interrupt handling and clean-up by 12*88e75cc3SDavid Brownell * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com> 13*88e75cc3SDavid Brownell * Cleanup and generalized support for voltage setting by 14*88e75cc3SDavid Brownell * Juha Yrjola 15*88e75cc3SDavid Brownell * Added support for controlling VCORE and regulator sleep states, 16*88e75cc3SDavid Brownell * Amit Kucheria <amit.kucheria@nokia.com> 17*88e75cc3SDavid Brownell * Copyright (C) 2005, 2006 Nokia Corporation 18*88e75cc3SDavid Brownell * 19*88e75cc3SDavid Brownell * This program is free software; you can redistribute it and/or modify 20*88e75cc3SDavid Brownell * it under the terms of the GNU General Public License as published by 21*88e75cc3SDavid Brownell * the Free Software Foundation; either version 2 of the License, or 22*88e75cc3SDavid Brownell * (at your option) any later version. 23*88e75cc3SDavid Brownell * 24*88e75cc3SDavid Brownell * This program is distributed in the hope that it will be useful, 25*88e75cc3SDavid Brownell * but WITHOUT ANY WARRANTY; without even the implied warranty of 26*88e75cc3SDavid Brownell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27*88e75cc3SDavid Brownell * GNU General Public License for more details. 28*88e75cc3SDavid Brownell * 29*88e75cc3SDavid Brownell * You should have received a copy of the GNU General Public License 30*88e75cc3SDavid Brownell * along with this program; if not, write to the Free Software 31*88e75cc3SDavid Brownell * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32*88e75cc3SDavid Brownell */ 33*88e75cc3SDavid Brownell 34*88e75cc3SDavid Brownell #include <linux/module.h> 35*88e75cc3SDavid Brownell #include <linux/i2c.h> 36*88e75cc3SDavid Brownell #include <linux/interrupt.h> 37*88e75cc3SDavid Brownell #include <linux/sched.h> 38*88e75cc3SDavid Brownell #include <linux/mutex.h> 39*88e75cc3SDavid Brownell #include <linux/workqueue.h> 40*88e75cc3SDavid Brownell #include <linux/delay.h> 41*88e75cc3SDavid Brownell #include <linux/rtc.h> 42*88e75cc3SDavid Brownell #include <linux/bcd.h> 43*88e75cc3SDavid Brownell 44*88e75cc3SDavid Brownell #include <asm/mach/irq.h> 45*88e75cc3SDavid Brownell 46*88e75cc3SDavid Brownell #include <mach/gpio.h> 47*88e75cc3SDavid Brownell #include <mach/menelaus.h> 48*88e75cc3SDavid Brownell 49*88e75cc3SDavid Brownell #define DRIVER_NAME "menelaus" 50*88e75cc3SDavid Brownell 51*88e75cc3SDavid Brownell #define MENELAUS_I2C_ADDRESS 0x72 52*88e75cc3SDavid Brownell 53*88e75cc3SDavid Brownell #define MENELAUS_REV 0x01 54*88e75cc3SDavid Brownell #define MENELAUS_VCORE_CTRL1 0x02 55*88e75cc3SDavid Brownell #define MENELAUS_VCORE_CTRL2 0x03 56*88e75cc3SDavid Brownell #define MENELAUS_VCORE_CTRL3 0x04 57*88e75cc3SDavid Brownell #define MENELAUS_VCORE_CTRL4 0x05 58*88e75cc3SDavid Brownell #define MENELAUS_VCORE_CTRL5 0x06 59*88e75cc3SDavid Brownell #define MENELAUS_DCDC_CTRL1 0x07 60*88e75cc3SDavid Brownell #define MENELAUS_DCDC_CTRL2 0x08 61*88e75cc3SDavid Brownell #define MENELAUS_DCDC_CTRL3 0x09 62*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL1 0x0A 63*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL2 0x0B 64*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL3 0x0C 65*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL4 0x0D 66*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL5 0x0E 67*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL6 0x0F 68*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL7 0x10 69*88e75cc3SDavid Brownell #define MENELAUS_LDO_CTRL8 0x11 70*88e75cc3SDavid Brownell #define MENELAUS_SLEEP_CTRL1 0x12 71*88e75cc3SDavid Brownell #define MENELAUS_SLEEP_CTRL2 0x13 72*88e75cc3SDavid Brownell #define MENELAUS_DEVICE_OFF 0x14 73*88e75cc3SDavid Brownell #define MENELAUS_OSC_CTRL 0x15 74*88e75cc3SDavid Brownell #define MENELAUS_DETECT_CTRL 0x16 75*88e75cc3SDavid Brownell #define MENELAUS_INT_MASK1 0x17 76*88e75cc3SDavid Brownell #define MENELAUS_INT_MASK2 0x18 77*88e75cc3SDavid Brownell #define MENELAUS_INT_STATUS1 0x19 78*88e75cc3SDavid Brownell #define MENELAUS_INT_STATUS2 0x1A 79*88e75cc3SDavid Brownell #define MENELAUS_INT_ACK1 0x1B 80*88e75cc3SDavid Brownell #define MENELAUS_INT_ACK2 0x1C 81*88e75cc3SDavid Brownell #define MENELAUS_GPIO_CTRL 0x1D 82*88e75cc3SDavid Brownell #define MENELAUS_GPIO_IN 0x1E 83*88e75cc3SDavid Brownell #define MENELAUS_GPIO_OUT 0x1F 84*88e75cc3SDavid Brownell #define MENELAUS_BBSMS 0x20 85*88e75cc3SDavid Brownell #define MENELAUS_RTC_CTRL 0x21 86*88e75cc3SDavid Brownell #define MENELAUS_RTC_UPDATE 0x22 87*88e75cc3SDavid Brownell #define MENELAUS_RTC_SEC 0x23 88*88e75cc3SDavid Brownell #define MENELAUS_RTC_MIN 0x24 89*88e75cc3SDavid Brownell #define MENELAUS_RTC_HR 0x25 90*88e75cc3SDavid Brownell #define MENELAUS_RTC_DAY 0x26 91*88e75cc3SDavid Brownell #define MENELAUS_RTC_MON 0x27 92*88e75cc3SDavid Brownell #define MENELAUS_RTC_YR 0x28 93*88e75cc3SDavid Brownell #define MENELAUS_RTC_WKDAY 0x29 94*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_SEC 0x2A 95*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_MIN 0x2B 96*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_HR 0x2C 97*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_DAY 0x2D 98*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_MON 0x2E 99*88e75cc3SDavid Brownell #define MENELAUS_RTC_AL_YR 0x2F 100*88e75cc3SDavid Brownell #define MENELAUS_RTC_COMP_MSB 0x30 101*88e75cc3SDavid Brownell #define MENELAUS_RTC_COMP_LSB 0x31 102*88e75cc3SDavid Brownell #define MENELAUS_S1_PULL_EN 0x32 103*88e75cc3SDavid Brownell #define MENELAUS_S1_PULL_DIR 0x33 104*88e75cc3SDavid Brownell #define MENELAUS_S2_PULL_EN 0x34 105*88e75cc3SDavid Brownell #define MENELAUS_S2_PULL_DIR 0x35 106*88e75cc3SDavid Brownell #define MENELAUS_MCT_CTRL1 0x36 107*88e75cc3SDavid Brownell #define MENELAUS_MCT_CTRL2 0x37 108*88e75cc3SDavid Brownell #define MENELAUS_MCT_CTRL3 0x38 109*88e75cc3SDavid Brownell #define MENELAUS_MCT_PIN_ST 0x39 110*88e75cc3SDavid Brownell #define MENELAUS_DEBOUNCE1 0x3A 111*88e75cc3SDavid Brownell 112*88e75cc3SDavid Brownell #define IH_MENELAUS_IRQS 12 113*88e75cc3SDavid Brownell #define MENELAUS_MMC_S1CD_IRQ 0 /* MMC slot 1 card change */ 114*88e75cc3SDavid Brownell #define MENELAUS_MMC_S2CD_IRQ 1 /* MMC slot 2 card change */ 115*88e75cc3SDavid Brownell #define MENELAUS_MMC_S1D1_IRQ 2 /* MMC DAT1 low in slot 1 */ 116*88e75cc3SDavid Brownell #define MENELAUS_MMC_S2D1_IRQ 3 /* MMC DAT1 low in slot 2 */ 117*88e75cc3SDavid Brownell #define MENELAUS_LOWBAT_IRQ 4 /* Low battery */ 118*88e75cc3SDavid Brownell #define MENELAUS_HOTDIE_IRQ 5 /* Hot die detect */ 119*88e75cc3SDavid Brownell #define MENELAUS_UVLO_IRQ 6 /* UVLO detect */ 120*88e75cc3SDavid Brownell #define MENELAUS_TSHUT_IRQ 7 /* Thermal shutdown */ 121*88e75cc3SDavid Brownell #define MENELAUS_RTCTMR_IRQ 8 /* RTC timer */ 122*88e75cc3SDavid Brownell #define MENELAUS_RTCALM_IRQ 9 /* RTC alarm */ 123*88e75cc3SDavid Brownell #define MENELAUS_RTCERR_IRQ 10 /* RTC error */ 124*88e75cc3SDavid Brownell #define MENELAUS_PSHBTN_IRQ 11 /* Push button */ 125*88e75cc3SDavid Brownell #define MENELAUS_RESERVED12_IRQ 12 /* Reserved */ 126*88e75cc3SDavid Brownell #define MENELAUS_RESERVED13_IRQ 13 /* Reserved */ 127*88e75cc3SDavid Brownell #define MENELAUS_RESERVED14_IRQ 14 /* Reserved */ 128*88e75cc3SDavid Brownell #define MENELAUS_RESERVED15_IRQ 15 /* Reserved */ 129*88e75cc3SDavid Brownell 130*88e75cc3SDavid Brownell static void menelaus_work(struct work_struct *_menelaus); 131*88e75cc3SDavid Brownell 132*88e75cc3SDavid Brownell struct menelaus_chip { 133*88e75cc3SDavid Brownell struct mutex lock; 134*88e75cc3SDavid Brownell struct i2c_client *client; 135*88e75cc3SDavid Brownell struct work_struct work; 136*88e75cc3SDavid Brownell #ifdef CONFIG_RTC_DRV_TWL92330 137*88e75cc3SDavid Brownell struct rtc_device *rtc; 138*88e75cc3SDavid Brownell u8 rtc_control; 139*88e75cc3SDavid Brownell unsigned uie:1; 140*88e75cc3SDavid Brownell #endif 141*88e75cc3SDavid Brownell unsigned vcore_hw_mode:1; 142*88e75cc3SDavid Brownell u8 mask1, mask2; 143*88e75cc3SDavid Brownell void (*handlers[16])(struct menelaus_chip *); 144*88e75cc3SDavid Brownell void (*mmc_callback)(void *data, u8 mask); 145*88e75cc3SDavid Brownell void *mmc_callback_data; 146*88e75cc3SDavid Brownell }; 147*88e75cc3SDavid Brownell 148*88e75cc3SDavid Brownell static struct menelaus_chip *the_menelaus; 149*88e75cc3SDavid Brownell 150*88e75cc3SDavid Brownell static int menelaus_write_reg(int reg, u8 value) 151*88e75cc3SDavid Brownell { 152*88e75cc3SDavid Brownell int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value); 153*88e75cc3SDavid Brownell 154*88e75cc3SDavid Brownell if (val < 0) { 155*88e75cc3SDavid Brownell pr_err(DRIVER_NAME ": write error"); 156*88e75cc3SDavid Brownell return val; 157*88e75cc3SDavid Brownell } 158*88e75cc3SDavid Brownell 159*88e75cc3SDavid Brownell return 0; 160*88e75cc3SDavid Brownell } 161*88e75cc3SDavid Brownell 162*88e75cc3SDavid Brownell static int menelaus_read_reg(int reg) 163*88e75cc3SDavid Brownell { 164*88e75cc3SDavid Brownell int val = i2c_smbus_read_byte_data(the_menelaus->client, reg); 165*88e75cc3SDavid Brownell 166*88e75cc3SDavid Brownell if (val < 0) 167*88e75cc3SDavid Brownell pr_err(DRIVER_NAME ": read error"); 168*88e75cc3SDavid Brownell 169*88e75cc3SDavid Brownell return val; 170*88e75cc3SDavid Brownell } 171*88e75cc3SDavid Brownell 172*88e75cc3SDavid Brownell static int menelaus_enable_irq(int irq) 173*88e75cc3SDavid Brownell { 174*88e75cc3SDavid Brownell if (irq > 7) { 175*88e75cc3SDavid Brownell irq -= 8; 176*88e75cc3SDavid Brownell the_menelaus->mask2 &= ~(1 << irq); 177*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_MASK2, 178*88e75cc3SDavid Brownell the_menelaus->mask2); 179*88e75cc3SDavid Brownell } else { 180*88e75cc3SDavid Brownell the_menelaus->mask1 &= ~(1 << irq); 181*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_MASK1, 182*88e75cc3SDavid Brownell the_menelaus->mask1); 183*88e75cc3SDavid Brownell } 184*88e75cc3SDavid Brownell } 185*88e75cc3SDavid Brownell 186*88e75cc3SDavid Brownell static int menelaus_disable_irq(int irq) 187*88e75cc3SDavid Brownell { 188*88e75cc3SDavid Brownell if (irq > 7) { 189*88e75cc3SDavid Brownell irq -= 8; 190*88e75cc3SDavid Brownell the_menelaus->mask2 |= (1 << irq); 191*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_MASK2, 192*88e75cc3SDavid Brownell the_menelaus->mask2); 193*88e75cc3SDavid Brownell } else { 194*88e75cc3SDavid Brownell the_menelaus->mask1 |= (1 << irq); 195*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_MASK1, 196*88e75cc3SDavid Brownell the_menelaus->mask1); 197*88e75cc3SDavid Brownell } 198*88e75cc3SDavid Brownell } 199*88e75cc3SDavid Brownell 200*88e75cc3SDavid Brownell static int menelaus_ack_irq(int irq) 201*88e75cc3SDavid Brownell { 202*88e75cc3SDavid Brownell if (irq > 7) 203*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_ACK2, 1 << (irq - 8)); 204*88e75cc3SDavid Brownell else 205*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_INT_ACK1, 1 << irq); 206*88e75cc3SDavid Brownell } 207*88e75cc3SDavid Brownell 208*88e75cc3SDavid Brownell /* Adds a handler for an interrupt. Does not run in interrupt context */ 209*88e75cc3SDavid Brownell static int menelaus_add_irq_work(int irq, 210*88e75cc3SDavid Brownell void (*handler)(struct menelaus_chip *)) 211*88e75cc3SDavid Brownell { 212*88e75cc3SDavid Brownell int ret = 0; 213*88e75cc3SDavid Brownell 214*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 215*88e75cc3SDavid Brownell the_menelaus->handlers[irq] = handler; 216*88e75cc3SDavid Brownell ret = menelaus_enable_irq(irq); 217*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 218*88e75cc3SDavid Brownell 219*88e75cc3SDavid Brownell return ret; 220*88e75cc3SDavid Brownell } 221*88e75cc3SDavid Brownell 222*88e75cc3SDavid Brownell /* Removes handler for an interrupt */ 223*88e75cc3SDavid Brownell static int menelaus_remove_irq_work(int irq) 224*88e75cc3SDavid Brownell { 225*88e75cc3SDavid Brownell int ret = 0; 226*88e75cc3SDavid Brownell 227*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 228*88e75cc3SDavid Brownell ret = menelaus_disable_irq(irq); 229*88e75cc3SDavid Brownell the_menelaus->handlers[irq] = NULL; 230*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 231*88e75cc3SDavid Brownell 232*88e75cc3SDavid Brownell return ret; 233*88e75cc3SDavid Brownell } 234*88e75cc3SDavid Brownell 235*88e75cc3SDavid Brownell /* 236*88e75cc3SDavid Brownell * Gets scheduled when a card detect interrupt happens. Note that in some cases 237*88e75cc3SDavid Brownell * this line is wired to card cover switch rather than the card detect switch 238*88e75cc3SDavid Brownell * in each slot. In this case the cards are not seen by menelaus. 239*88e75cc3SDavid Brownell * FIXME: Add handling for D1 too 240*88e75cc3SDavid Brownell */ 241*88e75cc3SDavid Brownell static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw) 242*88e75cc3SDavid Brownell { 243*88e75cc3SDavid Brownell int reg; 244*88e75cc3SDavid Brownell unsigned char card_mask = 0; 245*88e75cc3SDavid Brownell 246*88e75cc3SDavid Brownell reg = menelaus_read_reg(MENELAUS_MCT_PIN_ST); 247*88e75cc3SDavid Brownell if (reg < 0) 248*88e75cc3SDavid Brownell return; 249*88e75cc3SDavid Brownell 250*88e75cc3SDavid Brownell if (!(reg & 0x1)) 251*88e75cc3SDavid Brownell card_mask |= (1 << 0); 252*88e75cc3SDavid Brownell 253*88e75cc3SDavid Brownell if (!(reg & 0x2)) 254*88e75cc3SDavid Brownell card_mask |= (1 << 1); 255*88e75cc3SDavid Brownell 256*88e75cc3SDavid Brownell if (menelaus_hw->mmc_callback) 257*88e75cc3SDavid Brownell menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data, 258*88e75cc3SDavid Brownell card_mask); 259*88e75cc3SDavid Brownell } 260*88e75cc3SDavid Brownell 261*88e75cc3SDavid Brownell /* 262*88e75cc3SDavid Brownell * Toggles the MMC slots between open-drain and push-pull mode. 263*88e75cc3SDavid Brownell */ 264*88e75cc3SDavid Brownell int menelaus_set_mmc_opendrain(int slot, int enable) 265*88e75cc3SDavid Brownell { 266*88e75cc3SDavid Brownell int ret, val; 267*88e75cc3SDavid Brownell 268*88e75cc3SDavid Brownell if (slot != 1 && slot != 2) 269*88e75cc3SDavid Brownell return -EINVAL; 270*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 271*88e75cc3SDavid Brownell ret = menelaus_read_reg(MENELAUS_MCT_CTRL1); 272*88e75cc3SDavid Brownell if (ret < 0) { 273*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 274*88e75cc3SDavid Brownell return ret; 275*88e75cc3SDavid Brownell } 276*88e75cc3SDavid Brownell val = ret; 277*88e75cc3SDavid Brownell if (slot == 1) { 278*88e75cc3SDavid Brownell if (enable) 279*88e75cc3SDavid Brownell val |= 1 << 2; 280*88e75cc3SDavid Brownell else 281*88e75cc3SDavid Brownell val &= ~(1 << 2); 282*88e75cc3SDavid Brownell } else { 283*88e75cc3SDavid Brownell if (enable) 284*88e75cc3SDavid Brownell val |= 1 << 3; 285*88e75cc3SDavid Brownell else 286*88e75cc3SDavid Brownell val &= ~(1 << 3); 287*88e75cc3SDavid Brownell } 288*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val); 289*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 290*88e75cc3SDavid Brownell 291*88e75cc3SDavid Brownell return ret; 292*88e75cc3SDavid Brownell } 293*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_mmc_opendrain); 294*88e75cc3SDavid Brownell 295*88e75cc3SDavid Brownell int menelaus_set_slot_sel(int enable) 296*88e75cc3SDavid Brownell { 297*88e75cc3SDavid Brownell int ret; 298*88e75cc3SDavid Brownell 299*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 300*88e75cc3SDavid Brownell ret = menelaus_read_reg(MENELAUS_GPIO_CTRL); 301*88e75cc3SDavid Brownell if (ret < 0) 302*88e75cc3SDavid Brownell goto out; 303*88e75cc3SDavid Brownell ret |= 0x02; 304*88e75cc3SDavid Brownell if (enable) 305*88e75cc3SDavid Brownell ret |= 1 << 5; 306*88e75cc3SDavid Brownell else 307*88e75cc3SDavid Brownell ret &= ~(1 << 5); 308*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret); 309*88e75cc3SDavid Brownell out: 310*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 311*88e75cc3SDavid Brownell return ret; 312*88e75cc3SDavid Brownell } 313*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_slot_sel); 314*88e75cc3SDavid Brownell 315*88e75cc3SDavid Brownell int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en) 316*88e75cc3SDavid Brownell { 317*88e75cc3SDavid Brownell int ret, val; 318*88e75cc3SDavid Brownell 319*88e75cc3SDavid Brownell if (slot != 1 && slot != 2) 320*88e75cc3SDavid Brownell return -EINVAL; 321*88e75cc3SDavid Brownell if (power >= 3) 322*88e75cc3SDavid Brownell return -EINVAL; 323*88e75cc3SDavid Brownell 324*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 325*88e75cc3SDavid Brownell 326*88e75cc3SDavid Brownell ret = menelaus_read_reg(MENELAUS_MCT_CTRL2); 327*88e75cc3SDavid Brownell if (ret < 0) 328*88e75cc3SDavid Brownell goto out; 329*88e75cc3SDavid Brownell val = ret; 330*88e75cc3SDavid Brownell if (slot == 1) { 331*88e75cc3SDavid Brownell if (cd_en) 332*88e75cc3SDavid Brownell val |= (1 << 4) | (1 << 6); 333*88e75cc3SDavid Brownell else 334*88e75cc3SDavid Brownell val &= ~((1 << 4) | (1 << 6)); 335*88e75cc3SDavid Brownell } else { 336*88e75cc3SDavid Brownell if (cd_en) 337*88e75cc3SDavid Brownell val |= (1 << 5) | (1 << 7); 338*88e75cc3SDavid Brownell else 339*88e75cc3SDavid Brownell val &= ~((1 << 5) | (1 << 7)); 340*88e75cc3SDavid Brownell } 341*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val); 342*88e75cc3SDavid Brownell if (ret < 0) 343*88e75cc3SDavid Brownell goto out; 344*88e75cc3SDavid Brownell 345*88e75cc3SDavid Brownell ret = menelaus_read_reg(MENELAUS_MCT_CTRL3); 346*88e75cc3SDavid Brownell if (ret < 0) 347*88e75cc3SDavid Brownell goto out; 348*88e75cc3SDavid Brownell val = ret; 349*88e75cc3SDavid Brownell if (slot == 1) { 350*88e75cc3SDavid Brownell if (enable) 351*88e75cc3SDavid Brownell val |= 1 << 0; 352*88e75cc3SDavid Brownell else 353*88e75cc3SDavid Brownell val &= ~(1 << 0); 354*88e75cc3SDavid Brownell } else { 355*88e75cc3SDavid Brownell int b; 356*88e75cc3SDavid Brownell 357*88e75cc3SDavid Brownell if (enable) 358*88e75cc3SDavid Brownell ret |= 1 << 1; 359*88e75cc3SDavid Brownell else 360*88e75cc3SDavid Brownell ret &= ~(1 << 1); 361*88e75cc3SDavid Brownell b = menelaus_read_reg(MENELAUS_MCT_CTRL2); 362*88e75cc3SDavid Brownell b &= ~0x03; 363*88e75cc3SDavid Brownell b |= power; 364*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b); 365*88e75cc3SDavid Brownell if (ret < 0) 366*88e75cc3SDavid Brownell goto out; 367*88e75cc3SDavid Brownell } 368*88e75cc3SDavid Brownell /* Disable autonomous shutdown */ 369*88e75cc3SDavid Brownell val &= ~(0x03 << 2); 370*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val); 371*88e75cc3SDavid Brownell out: 372*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 373*88e75cc3SDavid Brownell return ret; 374*88e75cc3SDavid Brownell } 375*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_mmc_slot); 376*88e75cc3SDavid Brownell 377*88e75cc3SDavid Brownell int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask), 378*88e75cc3SDavid Brownell void *data) 379*88e75cc3SDavid Brownell { 380*88e75cc3SDavid Brownell int ret = 0; 381*88e75cc3SDavid Brownell 382*88e75cc3SDavid Brownell the_menelaus->mmc_callback_data = data; 383*88e75cc3SDavid Brownell the_menelaus->mmc_callback = callback; 384*88e75cc3SDavid Brownell ret = menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ, 385*88e75cc3SDavid Brownell menelaus_mmc_cd_work); 386*88e75cc3SDavid Brownell if (ret < 0) 387*88e75cc3SDavid Brownell return ret; 388*88e75cc3SDavid Brownell ret = menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ, 389*88e75cc3SDavid Brownell menelaus_mmc_cd_work); 390*88e75cc3SDavid Brownell if (ret < 0) 391*88e75cc3SDavid Brownell return ret; 392*88e75cc3SDavid Brownell ret = menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ, 393*88e75cc3SDavid Brownell menelaus_mmc_cd_work); 394*88e75cc3SDavid Brownell if (ret < 0) 395*88e75cc3SDavid Brownell return ret; 396*88e75cc3SDavid Brownell ret = menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ, 397*88e75cc3SDavid Brownell menelaus_mmc_cd_work); 398*88e75cc3SDavid Brownell 399*88e75cc3SDavid Brownell return ret; 400*88e75cc3SDavid Brownell } 401*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_register_mmc_callback); 402*88e75cc3SDavid Brownell 403*88e75cc3SDavid Brownell void menelaus_unregister_mmc_callback(void) 404*88e75cc3SDavid Brownell { 405*88e75cc3SDavid Brownell menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ); 406*88e75cc3SDavid Brownell menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ); 407*88e75cc3SDavid Brownell menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ); 408*88e75cc3SDavid Brownell menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ); 409*88e75cc3SDavid Brownell 410*88e75cc3SDavid Brownell the_menelaus->mmc_callback = NULL; 411*88e75cc3SDavid Brownell the_menelaus->mmc_callback_data = 0; 412*88e75cc3SDavid Brownell } 413*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_unregister_mmc_callback); 414*88e75cc3SDavid Brownell 415*88e75cc3SDavid Brownell struct menelaus_vtg { 416*88e75cc3SDavid Brownell const char *name; 417*88e75cc3SDavid Brownell u8 vtg_reg; 418*88e75cc3SDavid Brownell u8 vtg_shift; 419*88e75cc3SDavid Brownell u8 vtg_bits; 420*88e75cc3SDavid Brownell u8 mode_reg; 421*88e75cc3SDavid Brownell }; 422*88e75cc3SDavid Brownell 423*88e75cc3SDavid Brownell struct menelaus_vtg_value { 424*88e75cc3SDavid Brownell u16 vtg; 425*88e75cc3SDavid Brownell u16 val; 426*88e75cc3SDavid Brownell }; 427*88e75cc3SDavid Brownell 428*88e75cc3SDavid Brownell static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV, 429*88e75cc3SDavid Brownell int vtg_val, int mode) 430*88e75cc3SDavid Brownell { 431*88e75cc3SDavid Brownell int val, ret; 432*88e75cc3SDavid Brownell struct i2c_client *c = the_menelaus->client; 433*88e75cc3SDavid Brownell 434*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 435*88e75cc3SDavid Brownell if (vtg == 0) 436*88e75cc3SDavid Brownell goto set_voltage; 437*88e75cc3SDavid Brownell 438*88e75cc3SDavid Brownell ret = menelaus_read_reg(vtg->vtg_reg); 439*88e75cc3SDavid Brownell if (ret < 0) 440*88e75cc3SDavid Brownell goto out; 441*88e75cc3SDavid Brownell val = ret & ~(((1 << vtg->vtg_bits) - 1) << vtg->vtg_shift); 442*88e75cc3SDavid Brownell val |= vtg_val << vtg->vtg_shift; 443*88e75cc3SDavid Brownell 444*88e75cc3SDavid Brownell dev_dbg(&c->dev, "Setting voltage '%s'" 445*88e75cc3SDavid Brownell "to %d mV (reg 0x%02x, val 0x%02x)\n", 446*88e75cc3SDavid Brownell vtg->name, mV, vtg->vtg_reg, val); 447*88e75cc3SDavid Brownell 448*88e75cc3SDavid Brownell ret = menelaus_write_reg(vtg->vtg_reg, val); 449*88e75cc3SDavid Brownell if (ret < 0) 450*88e75cc3SDavid Brownell goto out; 451*88e75cc3SDavid Brownell set_voltage: 452*88e75cc3SDavid Brownell ret = menelaus_write_reg(vtg->mode_reg, mode); 453*88e75cc3SDavid Brownell out: 454*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 455*88e75cc3SDavid Brownell if (ret == 0) { 456*88e75cc3SDavid Brownell /* Wait for voltage to stabilize */ 457*88e75cc3SDavid Brownell msleep(1); 458*88e75cc3SDavid Brownell } 459*88e75cc3SDavid Brownell return ret; 460*88e75cc3SDavid Brownell } 461*88e75cc3SDavid Brownell 462*88e75cc3SDavid Brownell static int menelaus_get_vtg_value(int vtg, const struct menelaus_vtg_value *tbl, 463*88e75cc3SDavid Brownell int n) 464*88e75cc3SDavid Brownell { 465*88e75cc3SDavid Brownell int i; 466*88e75cc3SDavid Brownell 467*88e75cc3SDavid Brownell for (i = 0; i < n; i++, tbl++) 468*88e75cc3SDavid Brownell if (tbl->vtg == vtg) 469*88e75cc3SDavid Brownell return tbl->val; 470*88e75cc3SDavid Brownell return -EINVAL; 471*88e75cc3SDavid Brownell } 472*88e75cc3SDavid Brownell 473*88e75cc3SDavid Brownell /* 474*88e75cc3SDavid Brownell * Vcore can be programmed in two ways: 475*88e75cc3SDavid Brownell * SW-controlled: Required voltage is programmed into VCORE_CTRL1 476*88e75cc3SDavid Brownell * HW-controlled: Required range (roof-floor) is programmed into VCORE_CTRL3 477*88e75cc3SDavid Brownell * and VCORE_CTRL4 478*88e75cc3SDavid Brownell * 479*88e75cc3SDavid Brownell * Call correct 'set' function accordingly 480*88e75cc3SDavid Brownell */ 481*88e75cc3SDavid Brownell 482*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vcore_values[] = { 483*88e75cc3SDavid Brownell { 1000, 0 }, 484*88e75cc3SDavid Brownell { 1025, 1 }, 485*88e75cc3SDavid Brownell { 1050, 2 }, 486*88e75cc3SDavid Brownell { 1075, 3 }, 487*88e75cc3SDavid Brownell { 1100, 4 }, 488*88e75cc3SDavid Brownell { 1125, 5 }, 489*88e75cc3SDavid Brownell { 1150, 6 }, 490*88e75cc3SDavid Brownell { 1175, 7 }, 491*88e75cc3SDavid Brownell { 1200, 8 }, 492*88e75cc3SDavid Brownell { 1225, 9 }, 493*88e75cc3SDavid Brownell { 1250, 10 }, 494*88e75cc3SDavid Brownell { 1275, 11 }, 495*88e75cc3SDavid Brownell { 1300, 12 }, 496*88e75cc3SDavid Brownell { 1325, 13 }, 497*88e75cc3SDavid Brownell { 1350, 14 }, 498*88e75cc3SDavid Brownell { 1375, 15 }, 499*88e75cc3SDavid Brownell { 1400, 16 }, 500*88e75cc3SDavid Brownell { 1425, 17 }, 501*88e75cc3SDavid Brownell { 1450, 18 }, 502*88e75cc3SDavid Brownell }; 503*88e75cc3SDavid Brownell 504*88e75cc3SDavid Brownell int menelaus_set_vcore_sw(unsigned int mV) 505*88e75cc3SDavid Brownell { 506*88e75cc3SDavid Brownell int val, ret; 507*88e75cc3SDavid Brownell struct i2c_client *c = the_menelaus->client; 508*88e75cc3SDavid Brownell 509*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vcore_values, 510*88e75cc3SDavid Brownell ARRAY_SIZE(vcore_values)); 511*88e75cc3SDavid Brownell if (val < 0) 512*88e75cc3SDavid Brownell return -EINVAL; 513*88e75cc3SDavid Brownell 514*88e75cc3SDavid Brownell dev_dbg(&c->dev, "Setting VCORE to %d mV (val 0x%02x)\n", mV, val); 515*88e75cc3SDavid Brownell 516*88e75cc3SDavid Brownell /* Set SW mode and the voltage in one go. */ 517*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 518*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val); 519*88e75cc3SDavid Brownell if (ret == 0) 520*88e75cc3SDavid Brownell the_menelaus->vcore_hw_mode = 0; 521*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 522*88e75cc3SDavid Brownell msleep(1); 523*88e75cc3SDavid Brownell 524*88e75cc3SDavid Brownell return ret; 525*88e75cc3SDavid Brownell } 526*88e75cc3SDavid Brownell 527*88e75cc3SDavid Brownell int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV) 528*88e75cc3SDavid Brownell { 529*88e75cc3SDavid Brownell int fval, rval, val, ret; 530*88e75cc3SDavid Brownell struct i2c_client *c = the_menelaus->client; 531*88e75cc3SDavid Brownell 532*88e75cc3SDavid Brownell rval = menelaus_get_vtg_value(roof_mV, vcore_values, 533*88e75cc3SDavid Brownell ARRAY_SIZE(vcore_values)); 534*88e75cc3SDavid Brownell if (rval < 0) 535*88e75cc3SDavid Brownell return -EINVAL; 536*88e75cc3SDavid Brownell fval = menelaus_get_vtg_value(floor_mV, vcore_values, 537*88e75cc3SDavid Brownell ARRAY_SIZE(vcore_values)); 538*88e75cc3SDavid Brownell if (fval < 0) 539*88e75cc3SDavid Brownell return -EINVAL; 540*88e75cc3SDavid Brownell 541*88e75cc3SDavid Brownell dev_dbg(&c->dev, "Setting VCORE FLOOR to %d mV and ROOF to %d mV\n", 542*88e75cc3SDavid Brownell floor_mV, roof_mV); 543*88e75cc3SDavid Brownell 544*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 545*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_VCORE_CTRL3, fval); 546*88e75cc3SDavid Brownell if (ret < 0) 547*88e75cc3SDavid Brownell goto out; 548*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_VCORE_CTRL4, rval); 549*88e75cc3SDavid Brownell if (ret < 0) 550*88e75cc3SDavid Brownell goto out; 551*88e75cc3SDavid Brownell if (!the_menelaus->vcore_hw_mode) { 552*88e75cc3SDavid Brownell val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); 553*88e75cc3SDavid Brownell /* HW mode, turn OFF byte comparator */ 554*88e75cc3SDavid Brownell val |= ((1 << 7) | (1 << 5)); 555*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val); 556*88e75cc3SDavid Brownell the_menelaus->vcore_hw_mode = 1; 557*88e75cc3SDavid Brownell } 558*88e75cc3SDavid Brownell msleep(1); 559*88e75cc3SDavid Brownell out: 560*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 561*88e75cc3SDavid Brownell return ret; 562*88e75cc3SDavid Brownell } 563*88e75cc3SDavid Brownell 564*88e75cc3SDavid Brownell static const struct menelaus_vtg vmem_vtg = { 565*88e75cc3SDavid Brownell .name = "VMEM", 566*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_LDO_CTRL1, 567*88e75cc3SDavid Brownell .vtg_shift = 0, 568*88e75cc3SDavid Brownell .vtg_bits = 2, 569*88e75cc3SDavid Brownell .mode_reg = MENELAUS_LDO_CTRL3, 570*88e75cc3SDavid Brownell }; 571*88e75cc3SDavid Brownell 572*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vmem_values[] = { 573*88e75cc3SDavid Brownell { 1500, 0 }, 574*88e75cc3SDavid Brownell { 1800, 1 }, 575*88e75cc3SDavid Brownell { 1900, 2 }, 576*88e75cc3SDavid Brownell { 2500, 3 }, 577*88e75cc3SDavid Brownell }; 578*88e75cc3SDavid Brownell 579*88e75cc3SDavid Brownell int menelaus_set_vmem(unsigned int mV) 580*88e75cc3SDavid Brownell { 581*88e75cc3SDavid Brownell int val; 582*88e75cc3SDavid Brownell 583*88e75cc3SDavid Brownell if (mV == 0) 584*88e75cc3SDavid Brownell return menelaus_set_voltage(&vmem_vtg, 0, 0, 0); 585*88e75cc3SDavid Brownell 586*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vmem_values, ARRAY_SIZE(vmem_values)); 587*88e75cc3SDavid Brownell if (val < 0) 588*88e75cc3SDavid Brownell return -EINVAL; 589*88e75cc3SDavid Brownell return menelaus_set_voltage(&vmem_vtg, mV, val, 0x02); 590*88e75cc3SDavid Brownell } 591*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_vmem); 592*88e75cc3SDavid Brownell 593*88e75cc3SDavid Brownell static const struct menelaus_vtg vio_vtg = { 594*88e75cc3SDavid Brownell .name = "VIO", 595*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_LDO_CTRL1, 596*88e75cc3SDavid Brownell .vtg_shift = 2, 597*88e75cc3SDavid Brownell .vtg_bits = 2, 598*88e75cc3SDavid Brownell .mode_reg = MENELAUS_LDO_CTRL4, 599*88e75cc3SDavid Brownell }; 600*88e75cc3SDavid Brownell 601*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vio_values[] = { 602*88e75cc3SDavid Brownell { 1500, 0 }, 603*88e75cc3SDavid Brownell { 1800, 1 }, 604*88e75cc3SDavid Brownell { 2500, 2 }, 605*88e75cc3SDavid Brownell { 2800, 3 }, 606*88e75cc3SDavid Brownell }; 607*88e75cc3SDavid Brownell 608*88e75cc3SDavid Brownell int menelaus_set_vio(unsigned int mV) 609*88e75cc3SDavid Brownell { 610*88e75cc3SDavid Brownell int val; 611*88e75cc3SDavid Brownell 612*88e75cc3SDavid Brownell if (mV == 0) 613*88e75cc3SDavid Brownell return menelaus_set_voltage(&vio_vtg, 0, 0, 0); 614*88e75cc3SDavid Brownell 615*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vio_values, ARRAY_SIZE(vio_values)); 616*88e75cc3SDavid Brownell if (val < 0) 617*88e75cc3SDavid Brownell return -EINVAL; 618*88e75cc3SDavid Brownell return menelaus_set_voltage(&vio_vtg, mV, val, 0x02); 619*88e75cc3SDavid Brownell } 620*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_vio); 621*88e75cc3SDavid Brownell 622*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vdcdc_values[] = { 623*88e75cc3SDavid Brownell { 1500, 0 }, 624*88e75cc3SDavid Brownell { 1800, 1 }, 625*88e75cc3SDavid Brownell { 2000, 2 }, 626*88e75cc3SDavid Brownell { 2200, 3 }, 627*88e75cc3SDavid Brownell { 2400, 4 }, 628*88e75cc3SDavid Brownell { 2800, 5 }, 629*88e75cc3SDavid Brownell { 3000, 6 }, 630*88e75cc3SDavid Brownell { 3300, 7 }, 631*88e75cc3SDavid Brownell }; 632*88e75cc3SDavid Brownell 633*88e75cc3SDavid Brownell static const struct menelaus_vtg vdcdc2_vtg = { 634*88e75cc3SDavid Brownell .name = "VDCDC2", 635*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_DCDC_CTRL1, 636*88e75cc3SDavid Brownell .vtg_shift = 0, 637*88e75cc3SDavid Brownell .vtg_bits = 3, 638*88e75cc3SDavid Brownell .mode_reg = MENELAUS_DCDC_CTRL2, 639*88e75cc3SDavid Brownell }; 640*88e75cc3SDavid Brownell 641*88e75cc3SDavid Brownell static const struct menelaus_vtg vdcdc3_vtg = { 642*88e75cc3SDavid Brownell .name = "VDCDC3", 643*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_DCDC_CTRL1, 644*88e75cc3SDavid Brownell .vtg_shift = 3, 645*88e75cc3SDavid Brownell .vtg_bits = 3, 646*88e75cc3SDavid Brownell .mode_reg = MENELAUS_DCDC_CTRL3, 647*88e75cc3SDavid Brownell }; 648*88e75cc3SDavid Brownell 649*88e75cc3SDavid Brownell int menelaus_set_vdcdc(int dcdc, unsigned int mV) 650*88e75cc3SDavid Brownell { 651*88e75cc3SDavid Brownell const struct menelaus_vtg *vtg; 652*88e75cc3SDavid Brownell int val; 653*88e75cc3SDavid Brownell 654*88e75cc3SDavid Brownell if (dcdc != 2 && dcdc != 3) 655*88e75cc3SDavid Brownell return -EINVAL; 656*88e75cc3SDavid Brownell if (dcdc == 2) 657*88e75cc3SDavid Brownell vtg = &vdcdc2_vtg; 658*88e75cc3SDavid Brownell else 659*88e75cc3SDavid Brownell vtg = &vdcdc3_vtg; 660*88e75cc3SDavid Brownell 661*88e75cc3SDavid Brownell if (mV == 0) 662*88e75cc3SDavid Brownell return menelaus_set_voltage(vtg, 0, 0, 0); 663*88e75cc3SDavid Brownell 664*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vdcdc_values, 665*88e75cc3SDavid Brownell ARRAY_SIZE(vdcdc_values)); 666*88e75cc3SDavid Brownell if (val < 0) 667*88e75cc3SDavid Brownell return -EINVAL; 668*88e75cc3SDavid Brownell return menelaus_set_voltage(vtg, mV, val, 0x03); 669*88e75cc3SDavid Brownell } 670*88e75cc3SDavid Brownell 671*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vmmc_values[] = { 672*88e75cc3SDavid Brownell { 1850, 0 }, 673*88e75cc3SDavid Brownell { 2800, 1 }, 674*88e75cc3SDavid Brownell { 3000, 2 }, 675*88e75cc3SDavid Brownell { 3100, 3 }, 676*88e75cc3SDavid Brownell }; 677*88e75cc3SDavid Brownell 678*88e75cc3SDavid Brownell static const struct menelaus_vtg vmmc_vtg = { 679*88e75cc3SDavid Brownell .name = "VMMC", 680*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_LDO_CTRL1, 681*88e75cc3SDavid Brownell .vtg_shift = 6, 682*88e75cc3SDavid Brownell .vtg_bits = 2, 683*88e75cc3SDavid Brownell .mode_reg = MENELAUS_LDO_CTRL7, 684*88e75cc3SDavid Brownell }; 685*88e75cc3SDavid Brownell 686*88e75cc3SDavid Brownell int menelaus_set_vmmc(unsigned int mV) 687*88e75cc3SDavid Brownell { 688*88e75cc3SDavid Brownell int val; 689*88e75cc3SDavid Brownell 690*88e75cc3SDavid Brownell if (mV == 0) 691*88e75cc3SDavid Brownell return menelaus_set_voltage(&vmmc_vtg, 0, 0, 0); 692*88e75cc3SDavid Brownell 693*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vmmc_values, ARRAY_SIZE(vmmc_values)); 694*88e75cc3SDavid Brownell if (val < 0) 695*88e75cc3SDavid Brownell return -EINVAL; 696*88e75cc3SDavid Brownell return menelaus_set_voltage(&vmmc_vtg, mV, val, 0x02); 697*88e75cc3SDavid Brownell } 698*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_vmmc); 699*88e75cc3SDavid Brownell 700*88e75cc3SDavid Brownell 701*88e75cc3SDavid Brownell static const struct menelaus_vtg_value vaux_values[] = { 702*88e75cc3SDavid Brownell { 1500, 0 }, 703*88e75cc3SDavid Brownell { 1800, 1 }, 704*88e75cc3SDavid Brownell { 2500, 2 }, 705*88e75cc3SDavid Brownell { 2800, 3 }, 706*88e75cc3SDavid Brownell }; 707*88e75cc3SDavid Brownell 708*88e75cc3SDavid Brownell static const struct menelaus_vtg vaux_vtg = { 709*88e75cc3SDavid Brownell .name = "VAUX", 710*88e75cc3SDavid Brownell .vtg_reg = MENELAUS_LDO_CTRL1, 711*88e75cc3SDavid Brownell .vtg_shift = 4, 712*88e75cc3SDavid Brownell .vtg_bits = 2, 713*88e75cc3SDavid Brownell .mode_reg = MENELAUS_LDO_CTRL6, 714*88e75cc3SDavid Brownell }; 715*88e75cc3SDavid Brownell 716*88e75cc3SDavid Brownell int menelaus_set_vaux(unsigned int mV) 717*88e75cc3SDavid Brownell { 718*88e75cc3SDavid Brownell int val; 719*88e75cc3SDavid Brownell 720*88e75cc3SDavid Brownell if (mV == 0) 721*88e75cc3SDavid Brownell return menelaus_set_voltage(&vaux_vtg, 0, 0, 0); 722*88e75cc3SDavid Brownell 723*88e75cc3SDavid Brownell val = menelaus_get_vtg_value(mV, vaux_values, ARRAY_SIZE(vaux_values)); 724*88e75cc3SDavid Brownell if (val < 0) 725*88e75cc3SDavid Brownell return -EINVAL; 726*88e75cc3SDavid Brownell return menelaus_set_voltage(&vaux_vtg, mV, val, 0x02); 727*88e75cc3SDavid Brownell } 728*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_set_vaux); 729*88e75cc3SDavid Brownell 730*88e75cc3SDavid Brownell int menelaus_get_slot_pin_states(void) 731*88e75cc3SDavid Brownell { 732*88e75cc3SDavid Brownell return menelaus_read_reg(MENELAUS_MCT_PIN_ST); 733*88e75cc3SDavid Brownell } 734*88e75cc3SDavid Brownell EXPORT_SYMBOL(menelaus_get_slot_pin_states); 735*88e75cc3SDavid Brownell 736*88e75cc3SDavid Brownell int menelaus_set_regulator_sleep(int enable, u32 val) 737*88e75cc3SDavid Brownell { 738*88e75cc3SDavid Brownell int t, ret; 739*88e75cc3SDavid Brownell struct i2c_client *c = the_menelaus->client; 740*88e75cc3SDavid Brownell 741*88e75cc3SDavid Brownell mutex_lock(&the_menelaus->lock); 742*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val); 743*88e75cc3SDavid Brownell if (ret < 0) 744*88e75cc3SDavid Brownell goto out; 745*88e75cc3SDavid Brownell 746*88e75cc3SDavid Brownell dev_dbg(&c->dev, "regulator sleep configuration: %02x\n", val); 747*88e75cc3SDavid Brownell 748*88e75cc3SDavid Brownell ret = menelaus_read_reg(MENELAUS_GPIO_CTRL); 749*88e75cc3SDavid Brownell if (ret < 0) 750*88e75cc3SDavid Brownell goto out; 751*88e75cc3SDavid Brownell t = ((1 << 6) | 0x04); 752*88e75cc3SDavid Brownell if (enable) 753*88e75cc3SDavid Brownell ret |= t; 754*88e75cc3SDavid Brownell else 755*88e75cc3SDavid Brownell ret &= ~t; 756*88e75cc3SDavid Brownell ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret); 757*88e75cc3SDavid Brownell out: 758*88e75cc3SDavid Brownell mutex_unlock(&the_menelaus->lock); 759*88e75cc3SDavid Brownell return ret; 760*88e75cc3SDavid Brownell } 761*88e75cc3SDavid Brownell 762*88e75cc3SDavid Brownell /*-----------------------------------------------------------------------*/ 763*88e75cc3SDavid Brownell 764*88e75cc3SDavid Brownell /* Handles Menelaus interrupts. Does not run in interrupt context */ 765*88e75cc3SDavid Brownell static void menelaus_work(struct work_struct *_menelaus) 766*88e75cc3SDavid Brownell { 767*88e75cc3SDavid Brownell struct menelaus_chip *menelaus = 768*88e75cc3SDavid Brownell container_of(_menelaus, struct menelaus_chip, work); 769*88e75cc3SDavid Brownell void (*handler)(struct menelaus_chip *menelaus); 770*88e75cc3SDavid Brownell 771*88e75cc3SDavid Brownell while (1) { 772*88e75cc3SDavid Brownell unsigned isr; 773*88e75cc3SDavid Brownell 774*88e75cc3SDavid Brownell isr = (menelaus_read_reg(MENELAUS_INT_STATUS2) 775*88e75cc3SDavid Brownell & ~menelaus->mask2) << 8; 776*88e75cc3SDavid Brownell isr |= menelaus_read_reg(MENELAUS_INT_STATUS1) 777*88e75cc3SDavid Brownell & ~menelaus->mask1; 778*88e75cc3SDavid Brownell if (!isr) 779*88e75cc3SDavid Brownell break; 780*88e75cc3SDavid Brownell 781*88e75cc3SDavid Brownell while (isr) { 782*88e75cc3SDavid Brownell int irq = fls(isr) - 1; 783*88e75cc3SDavid Brownell isr &= ~(1 << irq); 784*88e75cc3SDavid Brownell 785*88e75cc3SDavid Brownell mutex_lock(&menelaus->lock); 786*88e75cc3SDavid Brownell menelaus_disable_irq(irq); 787*88e75cc3SDavid Brownell menelaus_ack_irq(irq); 788*88e75cc3SDavid Brownell handler = menelaus->handlers[irq]; 789*88e75cc3SDavid Brownell if (handler) 790*88e75cc3SDavid Brownell handler(menelaus); 791*88e75cc3SDavid Brownell menelaus_enable_irq(irq); 792*88e75cc3SDavid Brownell mutex_unlock(&menelaus->lock); 793*88e75cc3SDavid Brownell } 794*88e75cc3SDavid Brownell } 795*88e75cc3SDavid Brownell enable_irq(menelaus->client->irq); 796*88e75cc3SDavid Brownell } 797*88e75cc3SDavid Brownell 798*88e75cc3SDavid Brownell /* 799*88e75cc3SDavid Brownell * We cannot use I2C in interrupt context, so we just schedule work. 800*88e75cc3SDavid Brownell */ 801*88e75cc3SDavid Brownell static irqreturn_t menelaus_irq(int irq, void *_menelaus) 802*88e75cc3SDavid Brownell { 803*88e75cc3SDavid Brownell struct menelaus_chip *menelaus = _menelaus; 804*88e75cc3SDavid Brownell 805*88e75cc3SDavid Brownell disable_irq_nosync(irq); 806*88e75cc3SDavid Brownell (void)schedule_work(&menelaus->work); 807*88e75cc3SDavid Brownell 808*88e75cc3SDavid Brownell return IRQ_HANDLED; 809*88e75cc3SDavid Brownell } 810*88e75cc3SDavid Brownell 811*88e75cc3SDavid Brownell /*-----------------------------------------------------------------------*/ 812*88e75cc3SDavid Brownell 813*88e75cc3SDavid Brownell /* 814*88e75cc3SDavid Brownell * The RTC needs to be set once, then it runs on backup battery power. 815*88e75cc3SDavid Brownell * It supports alarms, including system wake alarms (from some modes); 816*88e75cc3SDavid Brownell * and 1/second IRQs if requested. 817*88e75cc3SDavid Brownell */ 818*88e75cc3SDavid Brownell #ifdef CONFIG_RTC_DRV_TWL92330 819*88e75cc3SDavid Brownell 820*88e75cc3SDavid Brownell #define RTC_CTRL_RTC_EN (1 << 0) 821*88e75cc3SDavid Brownell #define RTC_CTRL_AL_EN (1 << 1) 822*88e75cc3SDavid Brownell #define RTC_CTRL_MODE12 (1 << 2) 823*88e75cc3SDavid Brownell #define RTC_CTRL_EVERY_MASK (3 << 3) 824*88e75cc3SDavid Brownell #define RTC_CTRL_EVERY_SEC (0 << 3) 825*88e75cc3SDavid Brownell #define RTC_CTRL_EVERY_MIN (1 << 3) 826*88e75cc3SDavid Brownell #define RTC_CTRL_EVERY_HR (2 << 3) 827*88e75cc3SDavid Brownell #define RTC_CTRL_EVERY_DAY (3 << 3) 828*88e75cc3SDavid Brownell 829*88e75cc3SDavid Brownell #define RTC_UPDATE_EVERY 0x08 830*88e75cc3SDavid Brownell 831*88e75cc3SDavid Brownell #define RTC_HR_PM (1 << 7) 832*88e75cc3SDavid Brownell 833*88e75cc3SDavid Brownell static void menelaus_to_time(char *regs, struct rtc_time *t) 834*88e75cc3SDavid Brownell { 835*88e75cc3SDavid Brownell t->tm_sec = bcd2bin(regs[0]); 836*88e75cc3SDavid Brownell t->tm_min = bcd2bin(regs[1]); 837*88e75cc3SDavid Brownell if (the_menelaus->rtc_control & RTC_CTRL_MODE12) { 838*88e75cc3SDavid Brownell t->tm_hour = bcd2bin(regs[2] & 0x1f) - 1; 839*88e75cc3SDavid Brownell if (regs[2] & RTC_HR_PM) 840*88e75cc3SDavid Brownell t->tm_hour += 12; 841*88e75cc3SDavid Brownell } else 842*88e75cc3SDavid Brownell t->tm_hour = bcd2bin(regs[2] & 0x3f); 843*88e75cc3SDavid Brownell t->tm_mday = bcd2bin(regs[3]); 844*88e75cc3SDavid Brownell t->tm_mon = bcd2bin(regs[4]) - 1; 845*88e75cc3SDavid Brownell t->tm_year = bcd2bin(regs[5]) + 100; 846*88e75cc3SDavid Brownell } 847*88e75cc3SDavid Brownell 848*88e75cc3SDavid Brownell static int time_to_menelaus(struct rtc_time *t, int regnum) 849*88e75cc3SDavid Brownell { 850*88e75cc3SDavid Brownell int hour, status; 851*88e75cc3SDavid Brownell 852*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, bin2bcd(t->tm_sec)); 853*88e75cc3SDavid Brownell if (status < 0) 854*88e75cc3SDavid Brownell goto fail; 855*88e75cc3SDavid Brownell 856*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, bin2bcd(t->tm_min)); 857*88e75cc3SDavid Brownell if (status < 0) 858*88e75cc3SDavid Brownell goto fail; 859*88e75cc3SDavid Brownell 860*88e75cc3SDavid Brownell if (the_menelaus->rtc_control & RTC_CTRL_MODE12) { 861*88e75cc3SDavid Brownell hour = t->tm_hour + 1; 862*88e75cc3SDavid Brownell if (hour > 12) 863*88e75cc3SDavid Brownell hour = RTC_HR_PM | bin2bcd(hour - 12); 864*88e75cc3SDavid Brownell else 865*88e75cc3SDavid Brownell hour = bin2bcd(hour); 866*88e75cc3SDavid Brownell } else 867*88e75cc3SDavid Brownell hour = bin2bcd(t->tm_hour); 868*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, hour); 869*88e75cc3SDavid Brownell if (status < 0) 870*88e75cc3SDavid Brownell goto fail; 871*88e75cc3SDavid Brownell 872*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mday)); 873*88e75cc3SDavid Brownell if (status < 0) 874*88e75cc3SDavid Brownell goto fail; 875*88e75cc3SDavid Brownell 876*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mon + 1)); 877*88e75cc3SDavid Brownell if (status < 0) 878*88e75cc3SDavid Brownell goto fail; 879*88e75cc3SDavid Brownell 880*88e75cc3SDavid Brownell status = menelaus_write_reg(regnum++, bin2bcd(t->tm_year - 100)); 881*88e75cc3SDavid Brownell if (status < 0) 882*88e75cc3SDavid Brownell goto fail; 883*88e75cc3SDavid Brownell 884*88e75cc3SDavid Brownell return 0; 885*88e75cc3SDavid Brownell fail: 886*88e75cc3SDavid Brownell dev_err(&the_menelaus->client->dev, "rtc write reg %02x, err %d\n", 887*88e75cc3SDavid Brownell --regnum, status); 888*88e75cc3SDavid Brownell return status; 889*88e75cc3SDavid Brownell } 890*88e75cc3SDavid Brownell 891*88e75cc3SDavid Brownell static int menelaus_read_time(struct device *dev, struct rtc_time *t) 892*88e75cc3SDavid Brownell { 893*88e75cc3SDavid Brownell struct i2c_msg msg[2]; 894*88e75cc3SDavid Brownell char regs[7]; 895*88e75cc3SDavid Brownell int status; 896*88e75cc3SDavid Brownell 897*88e75cc3SDavid Brownell /* block read date and time registers */ 898*88e75cc3SDavid Brownell regs[0] = MENELAUS_RTC_SEC; 899*88e75cc3SDavid Brownell 900*88e75cc3SDavid Brownell msg[0].addr = MENELAUS_I2C_ADDRESS; 901*88e75cc3SDavid Brownell msg[0].flags = 0; 902*88e75cc3SDavid Brownell msg[0].len = 1; 903*88e75cc3SDavid Brownell msg[0].buf = regs; 904*88e75cc3SDavid Brownell 905*88e75cc3SDavid Brownell msg[1].addr = MENELAUS_I2C_ADDRESS; 906*88e75cc3SDavid Brownell msg[1].flags = I2C_M_RD; 907*88e75cc3SDavid Brownell msg[1].len = sizeof(regs); 908*88e75cc3SDavid Brownell msg[1].buf = regs; 909*88e75cc3SDavid Brownell 910*88e75cc3SDavid Brownell status = i2c_transfer(the_menelaus->client->adapter, msg, 2); 911*88e75cc3SDavid Brownell if (status != 2) { 912*88e75cc3SDavid Brownell dev_err(dev, "%s error %d\n", "read", status); 913*88e75cc3SDavid Brownell return -EIO; 914*88e75cc3SDavid Brownell } 915*88e75cc3SDavid Brownell 916*88e75cc3SDavid Brownell menelaus_to_time(regs, t); 917*88e75cc3SDavid Brownell t->tm_wday = bcd2bin(regs[6]); 918*88e75cc3SDavid Brownell 919*88e75cc3SDavid Brownell return 0; 920*88e75cc3SDavid Brownell } 921*88e75cc3SDavid Brownell 922*88e75cc3SDavid Brownell static int menelaus_set_time(struct device *dev, struct rtc_time *t) 923*88e75cc3SDavid Brownell { 924*88e75cc3SDavid Brownell int status; 925*88e75cc3SDavid Brownell 926*88e75cc3SDavid Brownell /* write date and time registers */ 927*88e75cc3SDavid Brownell status = time_to_menelaus(t, MENELAUS_RTC_SEC); 928*88e75cc3SDavid Brownell if (status < 0) 929*88e75cc3SDavid Brownell return status; 930*88e75cc3SDavid Brownell status = menelaus_write_reg(MENELAUS_RTC_WKDAY, bin2bcd(t->tm_wday)); 931*88e75cc3SDavid Brownell if (status < 0) { 932*88e75cc3SDavid Brownell dev_err(&the_menelaus->client->dev, "rtc write reg %02x " 933*88e75cc3SDavid Brownell "err %d\n", MENELAUS_RTC_WKDAY, status); 934*88e75cc3SDavid Brownell return status; 935*88e75cc3SDavid Brownell } 936*88e75cc3SDavid Brownell 937*88e75cc3SDavid Brownell /* now commit the write */ 938*88e75cc3SDavid Brownell status = menelaus_write_reg(MENELAUS_RTC_UPDATE, RTC_UPDATE_EVERY); 939*88e75cc3SDavid Brownell if (status < 0) 940*88e75cc3SDavid Brownell dev_err(&the_menelaus->client->dev, "rtc commit time, err %d\n", 941*88e75cc3SDavid Brownell status); 942*88e75cc3SDavid Brownell 943*88e75cc3SDavid Brownell return 0; 944*88e75cc3SDavid Brownell } 945*88e75cc3SDavid Brownell 946*88e75cc3SDavid Brownell static int menelaus_read_alarm(struct device *dev, struct rtc_wkalrm *w) 947*88e75cc3SDavid Brownell { 948*88e75cc3SDavid Brownell struct i2c_msg msg[2]; 949*88e75cc3SDavid Brownell char regs[6]; 950*88e75cc3SDavid Brownell int status; 951*88e75cc3SDavid Brownell 952*88e75cc3SDavid Brownell /* block read alarm registers */ 953*88e75cc3SDavid Brownell regs[0] = MENELAUS_RTC_AL_SEC; 954*88e75cc3SDavid Brownell 955*88e75cc3SDavid Brownell msg[0].addr = MENELAUS_I2C_ADDRESS; 956*88e75cc3SDavid Brownell msg[0].flags = 0; 957*88e75cc3SDavid Brownell msg[0].len = 1; 958*88e75cc3SDavid Brownell msg[0].buf = regs; 959*88e75cc3SDavid Brownell 960*88e75cc3SDavid Brownell msg[1].addr = MENELAUS_I2C_ADDRESS; 961*88e75cc3SDavid Brownell msg[1].flags = I2C_M_RD; 962*88e75cc3SDavid Brownell msg[1].len = sizeof(regs); 963*88e75cc3SDavid Brownell msg[1].buf = regs; 964*88e75cc3SDavid Brownell 965*88e75cc3SDavid Brownell status = i2c_transfer(the_menelaus->client->adapter, msg, 2); 966*88e75cc3SDavid Brownell if (status != 2) { 967*88e75cc3SDavid Brownell dev_err(dev, "%s error %d\n", "alarm read", status); 968*88e75cc3SDavid Brownell return -EIO; 969*88e75cc3SDavid Brownell } 970*88e75cc3SDavid Brownell 971*88e75cc3SDavid Brownell menelaus_to_time(regs, &w->time); 972*88e75cc3SDavid Brownell 973*88e75cc3SDavid Brownell w->enabled = !!(the_menelaus->rtc_control & RTC_CTRL_AL_EN); 974*88e75cc3SDavid Brownell 975*88e75cc3SDavid Brownell /* NOTE we *could* check if actually pending... */ 976*88e75cc3SDavid Brownell w->pending = 0; 977*88e75cc3SDavid Brownell 978*88e75cc3SDavid Brownell return 0; 979*88e75cc3SDavid Brownell } 980*88e75cc3SDavid Brownell 981*88e75cc3SDavid Brownell static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w) 982*88e75cc3SDavid Brownell { 983*88e75cc3SDavid Brownell int status; 984*88e75cc3SDavid Brownell 985*88e75cc3SDavid Brownell if (the_menelaus->client->irq <= 0 && w->enabled) 986*88e75cc3SDavid Brownell return -ENODEV; 987*88e75cc3SDavid Brownell 988*88e75cc3SDavid Brownell /* clear previous alarm enable */ 989*88e75cc3SDavid Brownell if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) { 990*88e75cc3SDavid Brownell the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; 991*88e75cc3SDavid Brownell status = menelaus_write_reg(MENELAUS_RTC_CTRL, 992*88e75cc3SDavid Brownell the_menelaus->rtc_control); 993*88e75cc3SDavid Brownell if (status < 0) 994*88e75cc3SDavid Brownell return status; 995*88e75cc3SDavid Brownell } 996*88e75cc3SDavid Brownell 997*88e75cc3SDavid Brownell /* write alarm registers */ 998*88e75cc3SDavid Brownell status = time_to_menelaus(&w->time, MENELAUS_RTC_AL_SEC); 999*88e75cc3SDavid Brownell if (status < 0) 1000*88e75cc3SDavid Brownell return status; 1001*88e75cc3SDavid Brownell 1002*88e75cc3SDavid Brownell /* enable alarm if requested */ 1003*88e75cc3SDavid Brownell if (w->enabled) { 1004*88e75cc3SDavid Brownell the_menelaus->rtc_control |= RTC_CTRL_AL_EN; 1005*88e75cc3SDavid Brownell status = menelaus_write_reg(MENELAUS_RTC_CTRL, 1006*88e75cc3SDavid Brownell the_menelaus->rtc_control); 1007*88e75cc3SDavid Brownell } 1008*88e75cc3SDavid Brownell 1009*88e75cc3SDavid Brownell return status; 1010*88e75cc3SDavid Brownell } 1011*88e75cc3SDavid Brownell 1012*88e75cc3SDavid Brownell #ifdef CONFIG_RTC_INTF_DEV 1013*88e75cc3SDavid Brownell 1014*88e75cc3SDavid Brownell static void menelaus_rtc_update_work(struct menelaus_chip *m) 1015*88e75cc3SDavid Brownell { 1016*88e75cc3SDavid Brownell /* report 1/sec update */ 1017*88e75cc3SDavid Brownell local_irq_disable(); 1018*88e75cc3SDavid Brownell rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF); 1019*88e75cc3SDavid Brownell local_irq_enable(); 1020*88e75cc3SDavid Brownell } 1021*88e75cc3SDavid Brownell 1022*88e75cc3SDavid Brownell static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg) 1023*88e75cc3SDavid Brownell { 1024*88e75cc3SDavid Brownell int status; 1025*88e75cc3SDavid Brownell 1026*88e75cc3SDavid Brownell if (the_menelaus->client->irq <= 0) 1027*88e75cc3SDavid Brownell return -ENOIOCTLCMD; 1028*88e75cc3SDavid Brownell 1029*88e75cc3SDavid Brownell switch (cmd) { 1030*88e75cc3SDavid Brownell /* alarm IRQ */ 1031*88e75cc3SDavid Brownell case RTC_AIE_ON: 1032*88e75cc3SDavid Brownell if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) 1033*88e75cc3SDavid Brownell return 0; 1034*88e75cc3SDavid Brownell the_menelaus->rtc_control |= RTC_CTRL_AL_EN; 1035*88e75cc3SDavid Brownell break; 1036*88e75cc3SDavid Brownell case RTC_AIE_OFF: 1037*88e75cc3SDavid Brownell if (!(the_menelaus->rtc_control & RTC_CTRL_AL_EN)) 1038*88e75cc3SDavid Brownell return 0; 1039*88e75cc3SDavid Brownell the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; 1040*88e75cc3SDavid Brownell break; 1041*88e75cc3SDavid Brownell /* 1/second "update" IRQ */ 1042*88e75cc3SDavid Brownell case RTC_UIE_ON: 1043*88e75cc3SDavid Brownell if (the_menelaus->uie) 1044*88e75cc3SDavid Brownell return 0; 1045*88e75cc3SDavid Brownell status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ); 1046*88e75cc3SDavid Brownell status = menelaus_add_irq_work(MENELAUS_RTCTMR_IRQ, 1047*88e75cc3SDavid Brownell menelaus_rtc_update_work); 1048*88e75cc3SDavid Brownell if (status == 0) 1049*88e75cc3SDavid Brownell the_menelaus->uie = 1; 1050*88e75cc3SDavid Brownell return status; 1051*88e75cc3SDavid Brownell case RTC_UIE_OFF: 1052*88e75cc3SDavid Brownell if (!the_menelaus->uie) 1053*88e75cc3SDavid Brownell return 0; 1054*88e75cc3SDavid Brownell status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ); 1055*88e75cc3SDavid Brownell if (status == 0) 1056*88e75cc3SDavid Brownell the_menelaus->uie = 0; 1057*88e75cc3SDavid Brownell return status; 1058*88e75cc3SDavid Brownell default: 1059*88e75cc3SDavid Brownell return -ENOIOCTLCMD; 1060*88e75cc3SDavid Brownell } 1061*88e75cc3SDavid Brownell return menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control); 1062*88e75cc3SDavid Brownell } 1063*88e75cc3SDavid Brownell 1064*88e75cc3SDavid Brownell #else 1065*88e75cc3SDavid Brownell #define menelaus_ioctl NULL 1066*88e75cc3SDavid Brownell #endif 1067*88e75cc3SDavid Brownell 1068*88e75cc3SDavid Brownell /* REVISIT no compensation register support ... */ 1069*88e75cc3SDavid Brownell 1070*88e75cc3SDavid Brownell static const struct rtc_class_ops menelaus_rtc_ops = { 1071*88e75cc3SDavid Brownell .ioctl = menelaus_ioctl, 1072*88e75cc3SDavid Brownell .read_time = menelaus_read_time, 1073*88e75cc3SDavid Brownell .set_time = menelaus_set_time, 1074*88e75cc3SDavid Brownell .read_alarm = menelaus_read_alarm, 1075*88e75cc3SDavid Brownell .set_alarm = menelaus_set_alarm, 1076*88e75cc3SDavid Brownell }; 1077*88e75cc3SDavid Brownell 1078*88e75cc3SDavid Brownell static void menelaus_rtc_alarm_work(struct menelaus_chip *m) 1079*88e75cc3SDavid Brownell { 1080*88e75cc3SDavid Brownell /* report alarm */ 1081*88e75cc3SDavid Brownell local_irq_disable(); 1082*88e75cc3SDavid Brownell rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF); 1083*88e75cc3SDavid Brownell local_irq_enable(); 1084*88e75cc3SDavid Brownell 1085*88e75cc3SDavid Brownell /* then disable it; alarms are oneshot */ 1086*88e75cc3SDavid Brownell the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN; 1087*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control); 1088*88e75cc3SDavid Brownell } 1089*88e75cc3SDavid Brownell 1090*88e75cc3SDavid Brownell static inline void menelaus_rtc_init(struct menelaus_chip *m) 1091*88e75cc3SDavid Brownell { 1092*88e75cc3SDavid Brownell int alarm = (m->client->irq > 0); 1093*88e75cc3SDavid Brownell 1094*88e75cc3SDavid Brownell /* assume 32KDETEN pin is pulled high */ 1095*88e75cc3SDavid Brownell if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) { 1096*88e75cc3SDavid Brownell dev_dbg(&m->client->dev, "no 32k oscillator\n"); 1097*88e75cc3SDavid Brownell return; 1098*88e75cc3SDavid Brownell } 1099*88e75cc3SDavid Brownell 1100*88e75cc3SDavid Brownell /* support RTC alarm; it can issue wakeups */ 1101*88e75cc3SDavid Brownell if (alarm) { 1102*88e75cc3SDavid Brownell if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ, 1103*88e75cc3SDavid Brownell menelaus_rtc_alarm_work) < 0) { 1104*88e75cc3SDavid Brownell dev_err(&m->client->dev, "can't handle RTC alarm\n"); 1105*88e75cc3SDavid Brownell return; 1106*88e75cc3SDavid Brownell } 1107*88e75cc3SDavid Brownell device_init_wakeup(&m->client->dev, 1); 1108*88e75cc3SDavid Brownell } 1109*88e75cc3SDavid Brownell 1110*88e75cc3SDavid Brownell /* be sure RTC is enabled; allow 1/sec irqs; leave 12hr mode alone */ 1111*88e75cc3SDavid Brownell m->rtc_control = menelaus_read_reg(MENELAUS_RTC_CTRL); 1112*88e75cc3SDavid Brownell if (!(m->rtc_control & RTC_CTRL_RTC_EN) 1113*88e75cc3SDavid Brownell || (m->rtc_control & RTC_CTRL_AL_EN) 1114*88e75cc3SDavid Brownell || (m->rtc_control & RTC_CTRL_EVERY_MASK)) { 1115*88e75cc3SDavid Brownell if (!(m->rtc_control & RTC_CTRL_RTC_EN)) { 1116*88e75cc3SDavid Brownell dev_warn(&m->client->dev, "rtc clock needs setting\n"); 1117*88e75cc3SDavid Brownell m->rtc_control |= RTC_CTRL_RTC_EN; 1118*88e75cc3SDavid Brownell } 1119*88e75cc3SDavid Brownell m->rtc_control &= ~RTC_CTRL_EVERY_MASK; 1120*88e75cc3SDavid Brownell m->rtc_control &= ~RTC_CTRL_AL_EN; 1121*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control); 1122*88e75cc3SDavid Brownell } 1123*88e75cc3SDavid Brownell 1124*88e75cc3SDavid Brownell m->rtc = rtc_device_register(DRIVER_NAME, 1125*88e75cc3SDavid Brownell &m->client->dev, 1126*88e75cc3SDavid Brownell &menelaus_rtc_ops, THIS_MODULE); 1127*88e75cc3SDavid Brownell if (IS_ERR(m->rtc)) { 1128*88e75cc3SDavid Brownell if (alarm) { 1129*88e75cc3SDavid Brownell menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ); 1130*88e75cc3SDavid Brownell device_init_wakeup(&m->client->dev, 0); 1131*88e75cc3SDavid Brownell } 1132*88e75cc3SDavid Brownell dev_err(&m->client->dev, "can't register RTC: %d\n", 1133*88e75cc3SDavid Brownell (int) PTR_ERR(m->rtc)); 1134*88e75cc3SDavid Brownell the_menelaus->rtc = NULL; 1135*88e75cc3SDavid Brownell } 1136*88e75cc3SDavid Brownell } 1137*88e75cc3SDavid Brownell 1138*88e75cc3SDavid Brownell #else 1139*88e75cc3SDavid Brownell 1140*88e75cc3SDavid Brownell static inline void menelaus_rtc_init(struct menelaus_chip *m) 1141*88e75cc3SDavid Brownell { 1142*88e75cc3SDavid Brownell /* nothing */ 1143*88e75cc3SDavid Brownell } 1144*88e75cc3SDavid Brownell 1145*88e75cc3SDavid Brownell #endif 1146*88e75cc3SDavid Brownell 1147*88e75cc3SDavid Brownell /*-----------------------------------------------------------------------*/ 1148*88e75cc3SDavid Brownell 1149*88e75cc3SDavid Brownell static struct i2c_driver menelaus_i2c_driver; 1150*88e75cc3SDavid Brownell 1151*88e75cc3SDavid Brownell static int menelaus_probe(struct i2c_client *client, 1152*88e75cc3SDavid Brownell const struct i2c_device_id *id) 1153*88e75cc3SDavid Brownell { 1154*88e75cc3SDavid Brownell struct menelaus_chip *menelaus; 1155*88e75cc3SDavid Brownell int rev = 0, val; 1156*88e75cc3SDavid Brownell int err = 0; 1157*88e75cc3SDavid Brownell struct menelaus_platform_data *menelaus_pdata = 1158*88e75cc3SDavid Brownell client->dev.platform_data; 1159*88e75cc3SDavid Brownell 1160*88e75cc3SDavid Brownell if (the_menelaus) { 1161*88e75cc3SDavid Brownell dev_dbg(&client->dev, "only one %s for now\n", 1162*88e75cc3SDavid Brownell DRIVER_NAME); 1163*88e75cc3SDavid Brownell return -ENODEV; 1164*88e75cc3SDavid Brownell } 1165*88e75cc3SDavid Brownell 1166*88e75cc3SDavid Brownell menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL); 1167*88e75cc3SDavid Brownell if (!menelaus) 1168*88e75cc3SDavid Brownell return -ENOMEM; 1169*88e75cc3SDavid Brownell 1170*88e75cc3SDavid Brownell i2c_set_clientdata(client, menelaus); 1171*88e75cc3SDavid Brownell 1172*88e75cc3SDavid Brownell the_menelaus = menelaus; 1173*88e75cc3SDavid Brownell menelaus->client = client; 1174*88e75cc3SDavid Brownell 1175*88e75cc3SDavid Brownell /* If a true probe check the device */ 1176*88e75cc3SDavid Brownell rev = menelaus_read_reg(MENELAUS_REV); 1177*88e75cc3SDavid Brownell if (rev < 0) { 1178*88e75cc3SDavid Brownell pr_err(DRIVER_NAME ": device not found"); 1179*88e75cc3SDavid Brownell err = -ENODEV; 1180*88e75cc3SDavid Brownell goto fail1; 1181*88e75cc3SDavid Brownell } 1182*88e75cc3SDavid Brownell 1183*88e75cc3SDavid Brownell /* Ack and disable all Menelaus interrupts */ 1184*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_INT_ACK1, 0xff); 1185*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_INT_ACK2, 0xff); 1186*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_INT_MASK1, 0xff); 1187*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_INT_MASK2, 0xff); 1188*88e75cc3SDavid Brownell menelaus->mask1 = 0xff; 1189*88e75cc3SDavid Brownell menelaus->mask2 = 0xff; 1190*88e75cc3SDavid Brownell 1191*88e75cc3SDavid Brownell /* Set output buffer strengths */ 1192*88e75cc3SDavid Brownell menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73); 1193*88e75cc3SDavid Brownell 1194*88e75cc3SDavid Brownell if (client->irq > 0) { 1195*88e75cc3SDavid Brownell err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED, 1196*88e75cc3SDavid Brownell DRIVER_NAME, menelaus); 1197*88e75cc3SDavid Brownell if (err) { 1198*88e75cc3SDavid Brownell dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", 1199*88e75cc3SDavid Brownell client->irq, err); 1200*88e75cc3SDavid Brownell goto fail1; 1201*88e75cc3SDavid Brownell } 1202*88e75cc3SDavid Brownell } 1203*88e75cc3SDavid Brownell 1204*88e75cc3SDavid Brownell mutex_init(&menelaus->lock); 1205*88e75cc3SDavid Brownell INIT_WORK(&menelaus->work, menelaus_work); 1206*88e75cc3SDavid Brownell 1207*88e75cc3SDavid Brownell pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f); 1208*88e75cc3SDavid Brownell 1209*88e75cc3SDavid Brownell val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); 1210*88e75cc3SDavid Brownell if (val < 0) 1211*88e75cc3SDavid Brownell goto fail2; 1212*88e75cc3SDavid Brownell if (val & (1 << 7)) 1213*88e75cc3SDavid Brownell menelaus->vcore_hw_mode = 1; 1214*88e75cc3SDavid Brownell else 1215*88e75cc3SDavid Brownell menelaus->vcore_hw_mode = 0; 1216*88e75cc3SDavid Brownell 1217*88e75cc3SDavid Brownell if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) { 1218*88e75cc3SDavid Brownell err = menelaus_pdata->late_init(&client->dev); 1219*88e75cc3SDavid Brownell if (err < 0) 1220*88e75cc3SDavid Brownell goto fail2; 1221*88e75cc3SDavid Brownell } 1222*88e75cc3SDavid Brownell 1223*88e75cc3SDavid Brownell menelaus_rtc_init(menelaus); 1224*88e75cc3SDavid Brownell 1225*88e75cc3SDavid Brownell return 0; 1226*88e75cc3SDavid Brownell fail2: 1227*88e75cc3SDavid Brownell free_irq(client->irq, menelaus); 1228*88e75cc3SDavid Brownell flush_scheduled_work(); 1229*88e75cc3SDavid Brownell fail1: 1230*88e75cc3SDavid Brownell kfree(menelaus); 1231*88e75cc3SDavid Brownell return err; 1232*88e75cc3SDavid Brownell } 1233*88e75cc3SDavid Brownell 1234*88e75cc3SDavid Brownell static int __exit menelaus_remove(struct i2c_client *client) 1235*88e75cc3SDavid Brownell { 1236*88e75cc3SDavid Brownell struct menelaus_chip *menelaus = i2c_get_clientdata(client); 1237*88e75cc3SDavid Brownell 1238*88e75cc3SDavid Brownell free_irq(client->irq, menelaus); 1239*88e75cc3SDavid Brownell kfree(menelaus); 1240*88e75cc3SDavid Brownell i2c_set_clientdata(client, NULL); 1241*88e75cc3SDavid Brownell the_menelaus = NULL; 1242*88e75cc3SDavid Brownell return 0; 1243*88e75cc3SDavid Brownell } 1244*88e75cc3SDavid Brownell 1245*88e75cc3SDavid Brownell static const struct i2c_device_id menelaus_id[] = { 1246*88e75cc3SDavid Brownell { "menelaus", 0 }, 1247*88e75cc3SDavid Brownell { } 1248*88e75cc3SDavid Brownell }; 1249*88e75cc3SDavid Brownell MODULE_DEVICE_TABLE(i2c, menelaus_id); 1250*88e75cc3SDavid Brownell 1251*88e75cc3SDavid Brownell static struct i2c_driver menelaus_i2c_driver = { 1252*88e75cc3SDavid Brownell .driver = { 1253*88e75cc3SDavid Brownell .name = DRIVER_NAME, 1254*88e75cc3SDavid Brownell }, 1255*88e75cc3SDavid Brownell .probe = menelaus_probe, 1256*88e75cc3SDavid Brownell .remove = __exit_p(menelaus_remove), 1257*88e75cc3SDavid Brownell .id_table = menelaus_id, 1258*88e75cc3SDavid Brownell }; 1259*88e75cc3SDavid Brownell 1260*88e75cc3SDavid Brownell static int __init menelaus_init(void) 1261*88e75cc3SDavid Brownell { 1262*88e75cc3SDavid Brownell int res; 1263*88e75cc3SDavid Brownell 1264*88e75cc3SDavid Brownell res = i2c_add_driver(&menelaus_i2c_driver); 1265*88e75cc3SDavid Brownell if (res < 0) { 1266*88e75cc3SDavid Brownell pr_err(DRIVER_NAME ": driver registration failed\n"); 1267*88e75cc3SDavid Brownell return res; 1268*88e75cc3SDavid Brownell } 1269*88e75cc3SDavid Brownell 1270*88e75cc3SDavid Brownell return 0; 1271*88e75cc3SDavid Brownell } 1272*88e75cc3SDavid Brownell 1273*88e75cc3SDavid Brownell static void __exit menelaus_exit(void) 1274*88e75cc3SDavid Brownell { 1275*88e75cc3SDavid Brownell i2c_del_driver(&menelaus_i2c_driver); 1276*88e75cc3SDavid Brownell 1277*88e75cc3SDavid Brownell /* FIXME: Shutdown menelaus parts that can be shut down */ 1278*88e75cc3SDavid Brownell } 1279*88e75cc3SDavid Brownell 1280*88e75cc3SDavid Brownell MODULE_AUTHOR("Texas Instruments, Inc. (and others)"); 1281*88e75cc3SDavid Brownell MODULE_DESCRIPTION("I2C interface for Menelaus."); 1282*88e75cc3SDavid Brownell MODULE_LICENSE("GPL"); 1283*88e75cc3SDavid Brownell 1284*88e75cc3SDavid Brownell module_init(menelaus_init); 1285*88e75cc3SDavid Brownell module_exit(menelaus_exit); 1286