313 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* NXP PCF50633 Power Management Unit (PMU) driver3 *4 * (C) 2006-2008 by Openmoko, Inc.5 * Author: Harald Welte <laforge@openmoko.org>6 * Balaji Rao <balajirrao@openmoko.org>7 * All rights reserved.8 */9 10#include <linux/i2c.h>11#include <linux/interrupt.h>12#include <linux/kernel.h>13#include <linux/mutex.h>14#include <linux/export.h>15#include <linux/slab.h>16 17#include <linux/mfd/pcf50633/core.h>18#include <linux/mfd/pcf50633/mbc.h>19 20int pcf50633_register_irq(struct pcf50633 *pcf, int irq,21 void (*handler) (int, void *), void *data)22{23 if (irq < 0 || irq >= PCF50633_NUM_IRQ || !handler)24 return -EINVAL;25 26 if (WARN_ON(pcf->irq_handler[irq].handler))27 return -EBUSY;28 29 mutex_lock(&pcf->lock);30 pcf->irq_handler[irq].handler = handler;31 pcf->irq_handler[irq].data = data;32 mutex_unlock(&pcf->lock);33 34 return 0;35}36EXPORT_SYMBOL_GPL(pcf50633_register_irq);37 38int pcf50633_free_irq(struct pcf50633 *pcf, int irq)39{40 if (irq < 0 || irq >= PCF50633_NUM_IRQ)41 return -EINVAL;42 43 mutex_lock(&pcf->lock);44 pcf->irq_handler[irq].handler = NULL;45 mutex_unlock(&pcf->lock);46 47 return 0;48}49EXPORT_SYMBOL_GPL(pcf50633_free_irq);50 51static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)52{53 u8 reg, bit;54 int idx;55 56 idx = irq >> 3;57 reg = PCF50633_REG_INT1M + idx;58 bit = 1 << (irq & 0x07);59 60 pcf50633_reg_set_bit_mask(pcf, reg, bit, mask ? bit : 0);61 62 mutex_lock(&pcf->lock);63 64 if (mask)65 pcf->mask_regs[idx] |= bit;66 else67 pcf->mask_regs[idx] &= ~bit;68 69 mutex_unlock(&pcf->lock);70 71 return 0;72}73 74int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)75{76 dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);77 78 return __pcf50633_irq_mask_set(pcf, irq, 1);79}80EXPORT_SYMBOL_GPL(pcf50633_irq_mask);81 82int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)83{84 dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);85 86 return __pcf50633_irq_mask_set(pcf, irq, 0);87}88EXPORT_SYMBOL_GPL(pcf50633_irq_unmask);89 90int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq)91{92 u8 reg, bits;93 94 reg = irq >> 3;95 bits = 1 << (irq & 0x07);96 97 return pcf->mask_regs[reg] & bits;98}99EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get);100 101static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq)102{103 if (pcf->irq_handler[irq].handler)104 pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data);105}106 107/* Maximum amount of time ONKEY is held before emergency action is taken */108#define PCF50633_ONKEY1S_TIMEOUT 8109 110static irqreturn_t pcf50633_irq(int irq, void *data)111{112 struct pcf50633 *pcf = data;113 int ret, i, j;114 u8 pcf_int[5], chgstat;115 116 /* Read the 5 INT regs in one transaction */117 ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,118 ARRAY_SIZE(pcf_int), pcf_int);119 if (ret != ARRAY_SIZE(pcf_int)) {120 dev_err(pcf->dev, "Error reading INT registers\n");121 122 /*123 * If this doesn't ACK the interrupt to the chip, we'll be124 * called once again as we're level triggered.125 */126 goto out;127 }128 129 /* defeat 8s death from lowsys on A5 */130 pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04);131 132 /* We immediately read the usb and adapter status. We thus make sure133 * only of USBINS/USBREM IRQ handlers are called */134 if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {135 chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);136 if (chgstat & (0x3 << 4))137 pcf_int[0] &= ~PCF50633_INT1_USBREM;138 else139 pcf_int[0] &= ~PCF50633_INT1_USBINS;140 }141 142 /* Make sure only one of ADPINS or ADPREM is set */143 if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {144 chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);145 if (chgstat & (0x3 << 4))146 pcf_int[0] &= ~PCF50633_INT1_ADPREM;147 else148 pcf_int[0] &= ~PCF50633_INT1_ADPINS;149 }150 151 dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "152 "INT4=0x%02x INT5=0x%02x\n", pcf_int[0],153 pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);154 155 /* Some revisions of the chip don't have a 8s standby mode on156 * ONKEY1S press. We try to manually do it in such cases. */157 if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {158 dev_info(pcf->dev, "ONKEY1S held for %d secs\n",159 pcf->onkey1s_held);160 if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)161 if (pcf->pdata->force_shutdown)162 pcf->pdata->force_shutdown(pcf);163 }164 165 if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {166 dev_info(pcf->dev, "ONKEY1S held\n");167 pcf->onkey1s_held = 1 ;168 169 /* Unmask IRQ_SECOND */170 pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,171 PCF50633_INT1_SECOND);172 173 /* Unmask IRQ_ONKEYR */174 pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,175 PCF50633_INT2_ONKEYR);176 }177 178 if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {179 pcf->onkey1s_held = 0;180 181 /* Mask SECOND and ONKEYR interrupts */182 if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)183 pcf50633_reg_set_bit_mask(pcf,184 PCF50633_REG_INT1M,185 PCF50633_INT1_SECOND,186 PCF50633_INT1_SECOND);187 188 if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)189 pcf50633_reg_set_bit_mask(pcf,190 PCF50633_REG_INT2M,191 PCF50633_INT2_ONKEYR,192 PCF50633_INT2_ONKEYR);193 }194 195 /* Have we just resumed ? */196 if (pcf->is_suspended) {197 pcf->is_suspended = 0;198 199 /* Set the resume reason filtering out non resumers */200 for (i = 0; i < ARRAY_SIZE(pcf_int); i++)201 pcf->resume_reason[i] = pcf_int[i] &202 pcf->pdata->resumers[i];203 204 /* Make sure we don't pass on any ONKEY events to205 * userspace now */206 pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);207 }208 209 for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {210 /* Unset masked interrupts */211 pcf_int[i] &= ~pcf->mask_regs[i];212 213 for (j = 0; j < 8 ; j++)214 if (pcf_int[i] & (1 << j))215 pcf50633_irq_call_handler(pcf, (i * 8) + j);216 }217 218out:219 return IRQ_HANDLED;220}221 222static int pcf50633_suspend(struct device *dev)223{224 struct i2c_client *client = to_i2c_client(dev);225 struct pcf50633 *pcf = i2c_get_clientdata(client);226 int ret;227 int i;228 u8 res[5];229 230 231 /* Make sure our interrupt handlers are not called232 * henceforth */233 disable_irq(pcf->irq);234 235 /* Save the masks */236 ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,237 ARRAY_SIZE(pcf->suspend_irq_masks),238 pcf->suspend_irq_masks);239 if (ret < 0) {240 dev_err(pcf->dev, "error saving irq masks\n");241 goto out;242 }243 244 /* Write wakeup irq masks */245 for (i = 0; i < ARRAY_SIZE(res); i++)246 res[i] = ~pcf->pdata->resumers[i];247 248 ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,249 ARRAY_SIZE(res), &res[0]);250 if (ret < 0) {251 dev_err(pcf->dev, "error writing wakeup irq masks\n");252 goto out;253 }254 255 pcf->is_suspended = 1;256 257out:258 return ret;259}260 261static int pcf50633_resume(struct device *dev)262{263 struct i2c_client *client = to_i2c_client(dev);264 struct pcf50633 *pcf = i2c_get_clientdata(client);265 int ret;266 267 /* Write the saved mask registers */268 ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,269 ARRAY_SIZE(pcf->suspend_irq_masks),270 pcf->suspend_irq_masks);271 if (ret < 0)272 dev_err(pcf->dev, "Error restoring saved suspend masks\n");273 274 enable_irq(pcf->irq);275 276 return ret;277}278 279EXPORT_GPL_SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);280 281int pcf50633_irq_init(struct pcf50633 *pcf, int irq)282{283 int ret;284 285 pcf->irq = irq;286 287 /* Enable all interrupts except RTC SECOND */288 pcf->mask_regs[0] = 0x80;289 pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);290 pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);291 pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);292 pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);293 pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);294 295 ret = request_threaded_irq(irq, NULL, pcf50633_irq,296 IRQF_TRIGGER_LOW | IRQF_ONESHOT,297 "pcf50633", pcf);298 299 if (ret)300 dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);301 302 if (enable_irq_wake(irq) < 0)303 dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"304 "in this hardware revision", irq);305 306 return ret;307}308 309void pcf50633_irq_free(struct pcf50633 *pcf)310{311 free_irq(pcf->irq, pcf);312}313