162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 662306a36Sopenharmony_ci * Author: Rabin Vincent <rabin.vincent@stericsson.com> 762306a36Sopenharmony_ci * Author: Mattias Wallin <mattias.wallin@stericsson.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/irq.h> 1462306a36Sopenharmony_ci#include <linux/irqdomain.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/moduleparam.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/mfd/core.h> 2062306a36Sopenharmony_ci#include <linux/mfd/abx500.h> 2162306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h> 2262306a36Sopenharmony_ci#include <linux/mfd/dbx500-prcmu.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Interrupt register offsets 2762306a36Sopenharmony_ci * Bank : 0x0E 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci#define AB8500_IT_SOURCE1_REG 0x00 3062306a36Sopenharmony_ci#define AB8500_IT_SOURCE2_REG 0x01 3162306a36Sopenharmony_ci#define AB8500_IT_SOURCE3_REG 0x02 3262306a36Sopenharmony_ci#define AB8500_IT_SOURCE4_REG 0x03 3362306a36Sopenharmony_ci#define AB8500_IT_SOURCE5_REG 0x04 3462306a36Sopenharmony_ci#define AB8500_IT_SOURCE6_REG 0x05 3562306a36Sopenharmony_ci#define AB8500_IT_SOURCE7_REG 0x06 3662306a36Sopenharmony_ci#define AB8500_IT_SOURCE8_REG 0x07 3762306a36Sopenharmony_ci#define AB9540_IT_SOURCE13_REG 0x0C 3862306a36Sopenharmony_ci#define AB8500_IT_SOURCE19_REG 0x12 3962306a36Sopenharmony_ci#define AB8500_IT_SOURCE20_REG 0x13 4062306a36Sopenharmony_ci#define AB8500_IT_SOURCE21_REG 0x14 4162306a36Sopenharmony_ci#define AB8500_IT_SOURCE22_REG 0x15 4262306a36Sopenharmony_ci#define AB8500_IT_SOURCE23_REG 0x16 4362306a36Sopenharmony_ci#define AB8500_IT_SOURCE24_REG 0x17 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * latch registers 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define AB8500_IT_LATCH1_REG 0x20 4962306a36Sopenharmony_ci#define AB8500_IT_LATCH2_REG 0x21 5062306a36Sopenharmony_ci#define AB8500_IT_LATCH3_REG 0x22 5162306a36Sopenharmony_ci#define AB8500_IT_LATCH4_REG 0x23 5262306a36Sopenharmony_ci#define AB8500_IT_LATCH5_REG 0x24 5362306a36Sopenharmony_ci#define AB8500_IT_LATCH6_REG 0x25 5462306a36Sopenharmony_ci#define AB8500_IT_LATCH7_REG 0x26 5562306a36Sopenharmony_ci#define AB8500_IT_LATCH8_REG 0x27 5662306a36Sopenharmony_ci#define AB8500_IT_LATCH9_REG 0x28 5762306a36Sopenharmony_ci#define AB8500_IT_LATCH10_REG 0x29 5862306a36Sopenharmony_ci#define AB8500_IT_LATCH12_REG 0x2B 5962306a36Sopenharmony_ci#define AB9540_IT_LATCH13_REG 0x2C 6062306a36Sopenharmony_ci#define AB8500_IT_LATCH19_REG 0x32 6162306a36Sopenharmony_ci#define AB8500_IT_LATCH20_REG 0x33 6262306a36Sopenharmony_ci#define AB8500_IT_LATCH21_REG 0x34 6362306a36Sopenharmony_ci#define AB8500_IT_LATCH22_REG 0x35 6462306a36Sopenharmony_ci#define AB8500_IT_LATCH23_REG 0x36 6562306a36Sopenharmony_ci#define AB8500_IT_LATCH24_REG 0x37 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * mask registers 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define AB8500_IT_MASK1_REG 0x40 7262306a36Sopenharmony_ci#define AB8500_IT_MASK2_REG 0x41 7362306a36Sopenharmony_ci#define AB8500_IT_MASK3_REG 0x42 7462306a36Sopenharmony_ci#define AB8500_IT_MASK4_REG 0x43 7562306a36Sopenharmony_ci#define AB8500_IT_MASK5_REG 0x44 7662306a36Sopenharmony_ci#define AB8500_IT_MASK6_REG 0x45 7762306a36Sopenharmony_ci#define AB8500_IT_MASK7_REG 0x46 7862306a36Sopenharmony_ci#define AB8500_IT_MASK8_REG 0x47 7962306a36Sopenharmony_ci#define AB8500_IT_MASK9_REG 0x48 8062306a36Sopenharmony_ci#define AB8500_IT_MASK10_REG 0x49 8162306a36Sopenharmony_ci#define AB8500_IT_MASK11_REG 0x4A 8262306a36Sopenharmony_ci#define AB8500_IT_MASK12_REG 0x4B 8362306a36Sopenharmony_ci#define AB8500_IT_MASK13_REG 0x4C 8462306a36Sopenharmony_ci#define AB8500_IT_MASK14_REG 0x4D 8562306a36Sopenharmony_ci#define AB8500_IT_MASK15_REG 0x4E 8662306a36Sopenharmony_ci#define AB8500_IT_MASK16_REG 0x4F 8762306a36Sopenharmony_ci#define AB8500_IT_MASK17_REG 0x50 8862306a36Sopenharmony_ci#define AB8500_IT_MASK18_REG 0x51 8962306a36Sopenharmony_ci#define AB8500_IT_MASK19_REG 0x52 9062306a36Sopenharmony_ci#define AB8500_IT_MASK20_REG 0x53 9162306a36Sopenharmony_ci#define AB8500_IT_MASK21_REG 0x54 9262306a36Sopenharmony_ci#define AB8500_IT_MASK22_REG 0x55 9362306a36Sopenharmony_ci#define AB8500_IT_MASK23_REG 0x56 9462306a36Sopenharmony_ci#define AB8500_IT_MASK24_REG 0x57 9562306a36Sopenharmony_ci#define AB8500_IT_MASK25_REG 0x58 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * latch hierarchy registers 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci#define AB8500_IT_LATCHHIER1_REG 0x60 10162306a36Sopenharmony_ci#define AB8500_IT_LATCHHIER2_REG 0x61 10262306a36Sopenharmony_ci#define AB8500_IT_LATCHHIER3_REG 0x62 10362306a36Sopenharmony_ci#define AB8540_IT_LATCHHIER4_REG 0x63 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define AB8500_IT_LATCHHIER_NUM 3 10662306a36Sopenharmony_ci#define AB8540_IT_LATCHHIER_NUM 4 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define AB8500_REV_REG 0x80 10962306a36Sopenharmony_ci#define AB8500_IC_NAME_REG 0x82 11062306a36Sopenharmony_ci#define AB8500_SWITCH_OFF_STATUS 0x00 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define AB8500_TURN_ON_STATUS 0x00 11362306a36Sopenharmony_ci#define AB8505_TURN_ON_STATUS_2 0x04 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define AB8500_CH_USBCH_STAT1_REG 0x02 11662306a36Sopenharmony_ci#define VBUS_DET_DBNC100 0x02 11762306a36Sopenharmony_ci#define VBUS_DET_DBNC1 0x01 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(on_stat_lock); 12062306a36Sopenharmony_cistatic u8 turn_on_stat_mask = 0xFF; 12162306a36Sopenharmony_cistatic u8 turn_on_stat_set; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define AB9540_MODEM_CTRL2_REG 0x23 12462306a36Sopenharmony_ci#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 12862306a36Sopenharmony_ci * numbers are indexed into this array with (num / 8). The interupts are 12962306a36Sopenharmony_ci * defined in linux/mfd/ab8500.h 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 13262306a36Sopenharmony_ci * offset 0. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci/* AB8500 support */ 13562306a36Sopenharmony_cistatic const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 13662306a36Sopenharmony_ci 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* AB9540 / AB8505 support */ 14062306a36Sopenharmony_cistatic const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 14162306a36Sopenharmony_ci 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* AB8540 support */ 14562306a36Sopenharmony_cistatic const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { 14662306a36Sopenharmony_ci 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 14762306a36Sopenharmony_ci 23, 25, 26, 27, 28, 29, 30, 31, 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic const char ab8500_version_str[][7] = { 15162306a36Sopenharmony_ci [AB8500_VERSION_AB8500] = "AB8500", 15262306a36Sopenharmony_ci [AB8500_VERSION_AB8505] = "AB8505", 15362306a36Sopenharmony_ci [AB8500_VERSION_AB9540] = "AB9540", 15462306a36Sopenharmony_ci [AB8500_VERSION_AB8540] = "AB8540", 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int ret; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 16262306a36Sopenharmony_ci if (ret < 0) 16362306a36Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 16462306a36Sopenharmony_ci return ret; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 16862306a36Sopenharmony_ci u8 data) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 17362306a36Sopenharmony_ci &mask, 1); 17462306a36Sopenharmony_ci if (ret < 0) 17562306a36Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 17662306a36Sopenharmony_ci return ret; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci int ret; 18262306a36Sopenharmony_ci u8 data; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 18562306a36Sopenharmony_ci if (ret < 0) { 18662306a36Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci return (int)data; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int ab8500_get_chip_id(struct device *dev) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct ab8500 *ab8500; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!dev) 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev->parent); 19962306a36Sopenharmony_ci return ab8500 ? (int)ab8500->chip_id : -EINVAL; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 20362306a36Sopenharmony_ci u8 reg, u8 data) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int ret; 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Put the u8 bank and u8 register together into a an u16. 20862306a36Sopenharmony_ci * The bank on higher 8 bits and register in lower 8 bits. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mutex_lock(&ab8500->lock); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci ret = ab8500->write(ab8500, addr, data); 21762306a36Sopenharmony_ci if (ret < 0) 21862306a36Sopenharmony_ci dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 21962306a36Sopenharmony_ci addr, ret); 22062306a36Sopenharmony_ci mutex_unlock(&ab8500->lock); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return ret; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int ab8500_set_register(struct device *dev, u8 bank, 22662306a36Sopenharmony_ci u8 reg, u8 value) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int ret; 22962306a36Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 23262306a36Sopenharmony_ci ret = set_register_interruptible(ab8500, bank, reg, value); 23362306a36Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 23462306a36Sopenharmony_ci return ret; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 23862306a36Sopenharmony_ci u8 reg, u8 *value) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int ret; 24162306a36Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci mutex_lock(&ab8500->lock); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ret = ab8500->read(ab8500, addr); 24662306a36Sopenharmony_ci if (ret < 0) 24762306a36Sopenharmony_ci dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 24862306a36Sopenharmony_ci addr, ret); 24962306a36Sopenharmony_ci else 25062306a36Sopenharmony_ci *value = ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci mutex_unlock(&ab8500->lock); 25362306a36Sopenharmony_ci dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int ab8500_get_register(struct device *dev, u8 bank, 25962306a36Sopenharmony_ci u8 reg, u8 *value) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 26562306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, bank, reg, value); 26662306a36Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 26762306a36Sopenharmony_ci return ret; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 27162306a36Sopenharmony_ci u8 reg, u8 bitmask, u8 bitvalues) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int ret; 27462306a36Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci mutex_lock(&ab8500->lock); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (ab8500->write_masked == NULL) { 27962306a36Sopenharmony_ci u8 data; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = ab8500->read(ab8500, addr); 28262306a36Sopenharmony_ci if (ret < 0) { 28362306a36Sopenharmony_ci dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 28462306a36Sopenharmony_ci addr, ret); 28562306a36Sopenharmony_ci goto out; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci data = (u8)ret; 28962306a36Sopenharmony_ci data = (~bitmask & data) | (bitmask & bitvalues); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ret = ab8500->write(ab8500, addr, data); 29262306a36Sopenharmony_ci if (ret < 0) 29362306a36Sopenharmony_ci dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 29462306a36Sopenharmony_ci addr, ret); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 29762306a36Sopenharmony_ci data); 29862306a36Sopenharmony_ci goto out; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 30162306a36Sopenharmony_ci if (ret < 0) 30262306a36Sopenharmony_ci dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 30362306a36Sopenharmony_ci ret); 30462306a36Sopenharmony_ciout: 30562306a36Sopenharmony_ci mutex_unlock(&ab8500->lock); 30662306a36Sopenharmony_ci return ret; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int ab8500_mask_and_set_register(struct device *dev, 31062306a36Sopenharmony_ci u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int ret; 31362306a36Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 31662306a36Sopenharmony_ci ret = mask_and_set_register_interruptible(ab8500, bank, reg, 31762306a36Sopenharmony_ci bitmask, bitvalues); 31862306a36Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic struct abx500_ops ab8500_ops = { 32362306a36Sopenharmony_ci .get_chip_id = ab8500_get_chip_id, 32462306a36Sopenharmony_ci .get_register = ab8500_get_register, 32562306a36Sopenharmony_ci .set_register = ab8500_set_register, 32662306a36Sopenharmony_ci .get_register_page = NULL, 32762306a36Sopenharmony_ci .set_register_page = NULL, 32862306a36Sopenharmony_ci .mask_and_set_register = ab8500_mask_and_set_register, 32962306a36Sopenharmony_ci .event_registers_startup_state_get = NULL, 33062306a36Sopenharmony_ci .startup_irq_enabled = NULL, 33162306a36Sopenharmony_ci .dump_all_banks = ab8500_dump_all_banks, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void ab8500_irq_lock(struct irq_data *data) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci mutex_lock(&ab8500->irq_lock); 33962306a36Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void ab8500_irq_sync_unlock(struct irq_data *data) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 34562306a36Sopenharmony_ci int i; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) { 34862306a36Sopenharmony_ci u8 old = ab8500->oldmask[i]; 34962306a36Sopenharmony_ci u8 new = ab8500->mask[i]; 35062306a36Sopenharmony_ci int reg; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (new == old) 35362306a36Sopenharmony_ci continue; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * Interrupt register 12 doesn't exist prior to AB8500 version 35762306a36Sopenharmony_ci * 2.0 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci if (ab8500->irq_reg_offset[i] == 11 && 36062306a36Sopenharmony_ci is_ab8500_1p1_or_earlier(ab8500)) 36162306a36Sopenharmony_ci continue; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (ab8500->irq_reg_offset[i] < 0) 36462306a36Sopenharmony_ci continue; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ab8500->oldmask[i] = new; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 36962306a36Sopenharmony_ci set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 37262306a36Sopenharmony_ci mutex_unlock(&ab8500->irq_lock); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void ab8500_irq_mask(struct irq_data *data) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 37862306a36Sopenharmony_ci int offset = data->hwirq; 37962306a36Sopenharmony_ci int index = offset / 8; 38062306a36Sopenharmony_ci int mask = 1 << (offset % 8); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ab8500->mask[index] |= mask; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 38562306a36Sopenharmony_ci if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 38662306a36Sopenharmony_ci ab8500->mask[index + 2] |= mask; 38762306a36Sopenharmony_ci if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 38862306a36Sopenharmony_ci ab8500->mask[index + 1] |= mask; 38962306a36Sopenharmony_ci if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 39062306a36Sopenharmony_ci /* Here the falling IRQ is one bit lower */ 39162306a36Sopenharmony_ci ab8500->mask[index] |= (mask << 1); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void ab8500_irq_unmask(struct irq_data *data) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 39762306a36Sopenharmony_ci unsigned int type = irqd_get_trigger_type(data); 39862306a36Sopenharmony_ci int offset = data->hwirq; 39962306a36Sopenharmony_ci int index = offset / 8; 40062306a36Sopenharmony_ci int mask = 1 << (offset % 8); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 40362306a36Sopenharmony_ci ab8500->mask[index] &= ~mask; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 40662306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) { 40762306a36Sopenharmony_ci if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 40862306a36Sopenharmony_ci ab8500->mask[index + 2] &= ~mask; 40962306a36Sopenharmony_ci else if (offset >= AB9540_INT_GPIO50R && 41062306a36Sopenharmony_ci offset <= AB9540_INT_GPIO54R) 41162306a36Sopenharmony_ci ab8500->mask[index + 1] &= ~mask; 41262306a36Sopenharmony_ci else if (offset == AB8540_INT_GPIO43R || 41362306a36Sopenharmony_ci offset == AB8540_INT_GPIO44R) 41462306a36Sopenharmony_ci /* Here the falling IRQ is one bit lower */ 41562306a36Sopenharmony_ci ab8500->mask[index] &= ~(mask << 1); 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci ab8500->mask[index] &= ~mask; 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci /* Satisfies the case where type is not set. */ 42062306a36Sopenharmony_ci ab8500->mask[index] &= ~mask; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic struct irq_chip ab8500_irq_chip = { 43062306a36Sopenharmony_ci .name = "ab8500", 43162306a36Sopenharmony_ci .irq_bus_lock = ab8500_irq_lock, 43262306a36Sopenharmony_ci .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 43362306a36Sopenharmony_ci .irq_mask = ab8500_irq_mask, 43462306a36Sopenharmony_ci .irq_disable = ab8500_irq_mask, 43562306a36Sopenharmony_ci .irq_unmask = ab8500_irq_unmask, 43662306a36Sopenharmony_ci .irq_set_type = ab8500_irq_set_type, 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void update_latch_offset(u8 *offset, int i) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci /* Fix inconsistent ITFromLatch25 bit mapping... */ 44262306a36Sopenharmony_ci if (unlikely(*offset == 17)) 44362306a36Sopenharmony_ci *offset = 24; 44462306a36Sopenharmony_ci /* Fix inconsistent ab8540 bit mapping... */ 44562306a36Sopenharmony_ci if (unlikely(*offset == 16)) 44662306a36Sopenharmony_ci *offset = 25; 44762306a36Sopenharmony_ci if ((i == 3) && (*offset >= 24)) 44862306a36Sopenharmony_ci *offset += 2; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 45262306a36Sopenharmony_ci int latch_offset, u8 latch_val) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci int int_bit, line, i; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) 45762306a36Sopenharmony_ci if (ab8500->irq_reg_offset[i] == latch_offset) 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (i >= ab8500->mask_size) { 46162306a36Sopenharmony_ci dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 46262306a36Sopenharmony_ci latch_offset); 46362306a36Sopenharmony_ci return -ENXIO; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* ignore masked out interrupts */ 46762306a36Sopenharmony_ci latch_val &= ~ab8500->mask[i]; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci while (latch_val) { 47062306a36Sopenharmony_ci int_bit = __ffs(latch_val); 47162306a36Sopenharmony_ci line = (i << 3) + int_bit; 47262306a36Sopenharmony_ci latch_val &= ~(1 << int_bit); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * This handles the falling edge hwirqs from the GPIO 47662306a36Sopenharmony_ci * lines. Route them back to the line registered for the 47762306a36Sopenharmony_ci * rising IRQ, as this is merely a flag for the same IRQ 47862306a36Sopenharmony_ci * in linux terms. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 48162306a36Sopenharmony_ci line -= 16; 48262306a36Sopenharmony_ci if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 48362306a36Sopenharmony_ci line -= 8; 48462306a36Sopenharmony_ci if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 48562306a36Sopenharmony_ci line += 1; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci handle_nested_irq(irq_find_mapping(ab8500->domain, line)); 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 49462306a36Sopenharmony_ci int hier_offset, u8 hier_val) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci int latch_bit, status; 49762306a36Sopenharmony_ci u8 latch_offset, latch_val; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci do { 50062306a36Sopenharmony_ci latch_bit = __ffs(hier_val); 50162306a36Sopenharmony_ci latch_offset = (hier_offset << 3) + latch_bit; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci update_latch_offset(&latch_offset, hier_offset); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci status = get_register_interruptible(ab8500, 50662306a36Sopenharmony_ci AB8500_INTERRUPT, 50762306a36Sopenharmony_ci AB8500_IT_LATCH1_REG + latch_offset, 50862306a36Sopenharmony_ci &latch_val); 50962306a36Sopenharmony_ci if (status < 0 || latch_val == 0) 51062306a36Sopenharmony_ci goto discard; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci status = ab8500_handle_hierarchical_line(ab8500, 51362306a36Sopenharmony_ci latch_offset, latch_val); 51462306a36Sopenharmony_ci if (status < 0) 51562306a36Sopenharmony_ci return status; 51662306a36Sopenharmony_cidiscard: 51762306a36Sopenharmony_ci hier_val &= ~(1 << latch_bit); 51862306a36Sopenharmony_ci } while (hier_val); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct ab8500 *ab8500 = dev; 52662306a36Sopenharmony_ci u8 i; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci dev_vdbg(ab8500->dev, "interrupt\n"); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Hierarchical interrupt version */ 53162306a36Sopenharmony_ci for (i = 0; i < (ab8500->it_latchhier_num); i++) { 53262306a36Sopenharmony_ci int status; 53362306a36Sopenharmony_ci u8 hier_val; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 53662306a36Sopenharmony_ci AB8500_IT_LATCHHIER1_REG + i, &hier_val); 53762306a36Sopenharmony_ci if (status < 0 || hier_val == 0) 53862306a36Sopenharmony_ci continue; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 54162306a36Sopenharmony_ci if (status < 0) 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci return IRQ_HANDLED; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 54862306a36Sopenharmony_ci irq_hw_number_t hwirq) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct ab8500 *ab8500 = d->host_data; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (!ab8500) 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci irq_set_chip_data(virq, ab8500); 55662306a36Sopenharmony_ci irq_set_chip_and_handler(virq, &ab8500_irq_chip, 55762306a36Sopenharmony_ci handle_simple_irq); 55862306a36Sopenharmony_ci irq_set_nested_thread(virq, 1); 55962306a36Sopenharmony_ci irq_set_noprobe(virq); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic const struct irq_domain_ops ab8500_irq_ops = { 56562306a36Sopenharmony_ci .map = ab8500_irq_map, 56662306a36Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 56762306a36Sopenharmony_ci}; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci int num_irqs; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (is_ab8540(ab8500)) 57462306a36Sopenharmony_ci num_irqs = AB8540_NR_IRQS; 57562306a36Sopenharmony_ci else if (is_ab9540(ab8500)) 57662306a36Sopenharmony_ci num_irqs = AB9540_NR_IRQS; 57762306a36Sopenharmony_ci else if (is_ab8505(ab8500)) 57862306a36Sopenharmony_ci num_irqs = AB8505_NR_IRQS; 57962306a36Sopenharmony_ci else 58062306a36Sopenharmony_ci num_irqs = AB8500_NR_IRQS; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* If ->irq_base is zero this will give a linear mapping */ 58362306a36Sopenharmony_ci ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, 58462306a36Sopenharmony_ci num_irqs, 0, 58562306a36Sopenharmony_ci &ab8500_irq_ops, ab8500); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!ab8500->domain) { 58862306a36Sopenharmony_ci dev_err(ab8500->dev, "Failed to create irqdomain\n"); 58962306a36Sopenharmony_ci return -ENODEV; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ciint ab8500_suspend(struct ab8500 *ab8500) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci if (atomic_read(&ab8500->transfer_ongoing)) 59862306a36Sopenharmony_ci return -EINVAL; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic const struct mfd_cell ab8500_bm_devs[] = { 60462306a36Sopenharmony_ci MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0, 60562306a36Sopenharmony_ci "stericsson,ab8500-charger"), 60662306a36Sopenharmony_ci MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0, 60762306a36Sopenharmony_ci "stericsson,ab8500-btemp"), 60862306a36Sopenharmony_ci MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0, 60962306a36Sopenharmony_ci "stericsson,ab8500-fg"), 61062306a36Sopenharmony_ci MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0, 61162306a36Sopenharmony_ci "stericsson,ab8500-chargalg"), 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic const struct mfd_cell ab8500_devs[] = { 61562306a36Sopenharmony_ci MFD_CELL_OF("ab8500-sysctrl", 61662306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), 61762306a36Sopenharmony_ci MFD_CELL_OF("ab8500-ext-regulator", 61862306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), 61962306a36Sopenharmony_ci MFD_CELL_OF("ab8500-regulator", 62062306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), 62162306a36Sopenharmony_ci MFD_CELL_OF("ab8500-clk", 62262306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-clk"), 62362306a36Sopenharmony_ci MFD_CELL_OF("ab8500-gpadc", 62462306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), 62562306a36Sopenharmony_ci MFD_CELL_OF("ab8500-rtc", 62662306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), 62762306a36Sopenharmony_ci MFD_CELL_OF("ab8500-acc-det", 62862306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), 62962306a36Sopenharmony_ci MFD_CELL_OF("ab8500-poweron-key", 63062306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), 63162306a36Sopenharmony_ci MFD_CELL_OF("ab8500-pwm", 63262306a36Sopenharmony_ci NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), 63362306a36Sopenharmony_ci MFD_CELL_OF("ab8500-pwm", 63462306a36Sopenharmony_ci NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), 63562306a36Sopenharmony_ci MFD_CELL_OF("ab8500-pwm", 63662306a36Sopenharmony_ci NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), 63762306a36Sopenharmony_ci MFD_CELL_OF("ab8500-denc", 63862306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-denc"), 63962306a36Sopenharmony_ci MFD_CELL_OF("pinctrl-ab8500", 64062306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), 64162306a36Sopenharmony_ci MFD_CELL_OF("abx500-temp", 64262306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,abx500-temp"), 64362306a36Sopenharmony_ci MFD_CELL_OF("ab8500-usb", 64462306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-usb"), 64562306a36Sopenharmony_ci MFD_CELL_OF("ab8500-codec", 64662306a36Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-codec"), 64762306a36Sopenharmony_ci}; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic const struct mfd_cell ab9540_devs[] = { 65062306a36Sopenharmony_ci { 65162306a36Sopenharmony_ci .name = "ab8500-sysctrl", 65262306a36Sopenharmony_ci }, 65362306a36Sopenharmony_ci { 65462306a36Sopenharmony_ci .name = "ab8500-ext-regulator", 65562306a36Sopenharmony_ci }, 65662306a36Sopenharmony_ci { 65762306a36Sopenharmony_ci .name = "ab8500-regulator", 65862306a36Sopenharmony_ci }, 65962306a36Sopenharmony_ci { 66062306a36Sopenharmony_ci .name = "abx500-clk", 66162306a36Sopenharmony_ci .of_compatible = "stericsson,abx500-clk", 66262306a36Sopenharmony_ci }, 66362306a36Sopenharmony_ci { 66462306a36Sopenharmony_ci .name = "ab8500-gpadc", 66562306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 66662306a36Sopenharmony_ci }, 66762306a36Sopenharmony_ci { 66862306a36Sopenharmony_ci .name = "ab8500-rtc", 66962306a36Sopenharmony_ci }, 67062306a36Sopenharmony_ci { 67162306a36Sopenharmony_ci .name = "ab8500-acc-det", 67262306a36Sopenharmony_ci }, 67362306a36Sopenharmony_ci { 67462306a36Sopenharmony_ci .name = "ab8500-poweron-key", 67562306a36Sopenharmony_ci }, 67662306a36Sopenharmony_ci { 67762306a36Sopenharmony_ci .name = "ab8500-pwm", 67862306a36Sopenharmony_ci .id = 1, 67962306a36Sopenharmony_ci }, 68062306a36Sopenharmony_ci { 68162306a36Sopenharmony_ci .name = "abx500-temp", 68262306a36Sopenharmony_ci }, 68362306a36Sopenharmony_ci { 68462306a36Sopenharmony_ci .name = "pinctrl-ab9540", 68562306a36Sopenharmony_ci .of_compatible = "stericsson,ab9540-gpio", 68662306a36Sopenharmony_ci }, 68762306a36Sopenharmony_ci { 68862306a36Sopenharmony_ci .name = "ab9540-usb", 68962306a36Sopenharmony_ci }, 69062306a36Sopenharmony_ci { 69162306a36Sopenharmony_ci .name = "ab9540-codec", 69262306a36Sopenharmony_ci }, 69362306a36Sopenharmony_ci { 69462306a36Sopenharmony_ci .name = "ab-iddet", 69562306a36Sopenharmony_ci }, 69662306a36Sopenharmony_ci}; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* Device list for ab8505 */ 69962306a36Sopenharmony_cistatic const struct mfd_cell ab8505_devs[] = { 70062306a36Sopenharmony_ci { 70162306a36Sopenharmony_ci .name = "ab8500-sysctrl", 70262306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-sysctrl", 70362306a36Sopenharmony_ci }, 70462306a36Sopenharmony_ci { 70562306a36Sopenharmony_ci .name = "ab8500-regulator", 70662306a36Sopenharmony_ci .of_compatible = "stericsson,ab8505-regulator", 70762306a36Sopenharmony_ci }, 70862306a36Sopenharmony_ci { 70962306a36Sopenharmony_ci .name = "abx500-clk", 71062306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-clk", 71162306a36Sopenharmony_ci }, 71262306a36Sopenharmony_ci { 71362306a36Sopenharmony_ci .name = "ab8500-gpadc", 71462306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 71562306a36Sopenharmony_ci }, 71662306a36Sopenharmony_ci { 71762306a36Sopenharmony_ci .name = "ab8500-rtc", 71862306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-rtc", 71962306a36Sopenharmony_ci }, 72062306a36Sopenharmony_ci { 72162306a36Sopenharmony_ci .name = "ab8500-acc-det", 72262306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-acc-det", 72362306a36Sopenharmony_ci }, 72462306a36Sopenharmony_ci { 72562306a36Sopenharmony_ci .name = "ab8500-poweron-key", 72662306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-poweron-key", 72762306a36Sopenharmony_ci }, 72862306a36Sopenharmony_ci { 72962306a36Sopenharmony_ci .name = "ab8500-pwm", 73062306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-pwm", 73162306a36Sopenharmony_ci .id = 1, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci { 73462306a36Sopenharmony_ci .name = "pinctrl-ab8505", 73562306a36Sopenharmony_ci .of_compatible = "stericsson,ab8505-gpio", 73662306a36Sopenharmony_ci }, 73762306a36Sopenharmony_ci { 73862306a36Sopenharmony_ci .name = "ab8500-usb", 73962306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-usb", 74062306a36Sopenharmony_ci }, 74162306a36Sopenharmony_ci { 74262306a36Sopenharmony_ci .name = "ab8500-codec", 74362306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-codec", 74462306a36Sopenharmony_ci }, 74562306a36Sopenharmony_ci { 74662306a36Sopenharmony_ci .name = "ab-iddet", 74762306a36Sopenharmony_ci }, 74862306a36Sopenharmony_ci}; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic const struct mfd_cell ab8540_devs[] = { 75162306a36Sopenharmony_ci { 75262306a36Sopenharmony_ci .name = "ab8500-sysctrl", 75362306a36Sopenharmony_ci }, 75462306a36Sopenharmony_ci { 75562306a36Sopenharmony_ci .name = "ab8500-ext-regulator", 75662306a36Sopenharmony_ci }, 75762306a36Sopenharmony_ci { 75862306a36Sopenharmony_ci .name = "ab8500-regulator", 75962306a36Sopenharmony_ci }, 76062306a36Sopenharmony_ci { 76162306a36Sopenharmony_ci .name = "abx500-clk", 76262306a36Sopenharmony_ci .of_compatible = "stericsson,abx500-clk", 76362306a36Sopenharmony_ci }, 76462306a36Sopenharmony_ci { 76562306a36Sopenharmony_ci .name = "ab8500-gpadc", 76662306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 76762306a36Sopenharmony_ci }, 76862306a36Sopenharmony_ci { 76962306a36Sopenharmony_ci .name = "ab8500-acc-det", 77062306a36Sopenharmony_ci }, 77162306a36Sopenharmony_ci { 77262306a36Sopenharmony_ci .name = "ab8500-poweron-key", 77362306a36Sopenharmony_ci }, 77462306a36Sopenharmony_ci { 77562306a36Sopenharmony_ci .name = "ab8500-pwm", 77662306a36Sopenharmony_ci .id = 1, 77762306a36Sopenharmony_ci }, 77862306a36Sopenharmony_ci { 77962306a36Sopenharmony_ci .name = "abx500-temp", 78062306a36Sopenharmony_ci }, 78162306a36Sopenharmony_ci { 78262306a36Sopenharmony_ci .name = "pinctrl-ab8540", 78362306a36Sopenharmony_ci }, 78462306a36Sopenharmony_ci { 78562306a36Sopenharmony_ci .name = "ab8540-usb", 78662306a36Sopenharmony_ci }, 78762306a36Sopenharmony_ci { 78862306a36Sopenharmony_ci .name = "ab8540-codec", 78962306a36Sopenharmony_ci }, 79062306a36Sopenharmony_ci { 79162306a36Sopenharmony_ci .name = "ab-iddet", 79262306a36Sopenharmony_ci }, 79362306a36Sopenharmony_ci}; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic const struct mfd_cell ab8540_cut1_devs[] = { 79662306a36Sopenharmony_ci { 79762306a36Sopenharmony_ci .name = "ab8500-rtc", 79862306a36Sopenharmony_ci .of_compatible = "stericsson,ab8500-rtc", 79962306a36Sopenharmony_ci }, 80062306a36Sopenharmony_ci}; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic const struct mfd_cell ab8540_cut2_devs[] = { 80362306a36Sopenharmony_ci { 80462306a36Sopenharmony_ci .name = "ab8540-rtc", 80562306a36Sopenharmony_ci .of_compatible = "stericsson,ab8540-rtc", 80662306a36Sopenharmony_ci }, 80762306a36Sopenharmony_ci}; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic ssize_t chip_id_show(struct device *dev, 81062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct ab8500 *ab8500; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* 82062306a36Sopenharmony_ci * ab8500 has switched off due to (SWITCH_OFF_STATUS): 82162306a36Sopenharmony_ci * 0x01 Swoff bit programming 82262306a36Sopenharmony_ci * 0x02 Thermal protection activation 82362306a36Sopenharmony_ci * 0x04 Vbat lower then BattOk falling threshold 82462306a36Sopenharmony_ci * 0x08 Watchdog expired 82562306a36Sopenharmony_ci * 0x10 Non presence of 32kHz clock 82662306a36Sopenharmony_ci * 0x20 Battery level lower than power on reset threshold 82762306a36Sopenharmony_ci * 0x40 Power on key 1 pressed longer than 10 seconds 82862306a36Sopenharmony_ci * 0x80 DB8500 thermal shutdown 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_cistatic ssize_t switch_off_status_show(struct device *dev, 83162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci int ret; 83462306a36Sopenharmony_ci u8 value; 83562306a36Sopenharmony_ci struct ab8500 *ab8500; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 83862306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_RTC, 83962306a36Sopenharmony_ci AB8500_SWITCH_OFF_STATUS, &value); 84062306a36Sopenharmony_ci if (ret < 0) 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci return sprintf(buf, "%#x\n", value); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci/* use mask and set to override the register turn_on_stat value */ 84662306a36Sopenharmony_civoid ab8500_override_turn_on_stat(u8 mask, u8 set) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci spin_lock(&on_stat_lock); 84962306a36Sopenharmony_ci turn_on_stat_mask = mask; 85062306a36Sopenharmony_ci turn_on_stat_set = set; 85162306a36Sopenharmony_ci spin_unlock(&on_stat_lock); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci/* 85562306a36Sopenharmony_ci * ab8500 has turned on due to (TURN_ON_STATUS): 85662306a36Sopenharmony_ci * 0x01 PORnVbat 85762306a36Sopenharmony_ci * 0x02 PonKey1dbF 85862306a36Sopenharmony_ci * 0x04 PonKey2dbF 85962306a36Sopenharmony_ci * 0x08 RTCAlarm 86062306a36Sopenharmony_ci * 0x10 MainChDet 86162306a36Sopenharmony_ci * 0x20 VbusDet 86262306a36Sopenharmony_ci * 0x40 UsbIDDetect 86362306a36Sopenharmony_ci * 0x80 Reserved 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_cistatic ssize_t turn_on_status_show(struct device *dev, 86662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci int ret; 86962306a36Sopenharmony_ci u8 value; 87062306a36Sopenharmony_ci struct ab8500 *ab8500; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 87362306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 87462306a36Sopenharmony_ci AB8500_TURN_ON_STATUS, &value); 87562306a36Sopenharmony_ci if (ret < 0) 87662306a36Sopenharmony_ci return ret; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* 87962306a36Sopenharmony_ci * In L9540, turn_on_status register is not updated correctly if 88062306a36Sopenharmony_ci * the device is rebooted with AC/USB charger connected. Due to 88162306a36Sopenharmony_ci * this, the device boots android instead of entering into charge 88262306a36Sopenharmony_ci * only mode. Read the AC/USB status register to detect the charger 88362306a36Sopenharmony_ci * presence and update the turn on status manually. 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_ci if (is_ab9540(ab8500)) { 88662306a36Sopenharmony_ci spin_lock(&on_stat_lock); 88762306a36Sopenharmony_ci value = (value & turn_on_stat_mask) | turn_on_stat_set; 88862306a36Sopenharmony_ci spin_unlock(&on_stat_lock); 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return sprintf(buf, "%#x\n", value); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic ssize_t turn_on_status_2_show(struct device *dev, 89562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci int ret; 89862306a36Sopenharmony_ci u8 value; 89962306a36Sopenharmony_ci struct ab8500 *ab8500; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 90262306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 90362306a36Sopenharmony_ci AB8505_TURN_ON_STATUS_2, &value); 90462306a36Sopenharmony_ci if (ret < 0) 90562306a36Sopenharmony_ci return ret; 90662306a36Sopenharmony_ci return sprintf(buf, "%#x\n", (value & 0x1)); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic ssize_t dbbrstn_show(struct device *dev, 91062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct ab8500 *ab8500; 91362306a36Sopenharmony_ci int ret; 91462306a36Sopenharmony_ci u8 value; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 91962306a36Sopenharmony_ci AB9540_MODEM_CTRL2_REG, &value); 92062306a36Sopenharmony_ci if (ret < 0) 92162306a36Sopenharmony_ci return ret; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return sprintf(buf, "%d\n", 92462306a36Sopenharmony_ci (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic ssize_t dbbrstn_store(struct device *dev, 92862306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct ab8500 *ab8500; 93162306a36Sopenharmony_ci int ret = count; 93262306a36Sopenharmony_ci int err; 93362306a36Sopenharmony_ci u8 bitvalues; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (count > 0) { 93862306a36Sopenharmony_ci switch (buf[0]) { 93962306a36Sopenharmony_ci case '0': 94062306a36Sopenharmony_ci bitvalues = 0; 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci case '1': 94362306a36Sopenharmony_ci bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci default: 94662306a36Sopenharmony_ci goto exit; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci err = mask_and_set_register_interruptible(ab8500, 95062306a36Sopenharmony_ci AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 95162306a36Sopenharmony_ci AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 95262306a36Sopenharmony_ci if (err) 95362306a36Sopenharmony_ci dev_info(ab8500->dev, 95462306a36Sopenharmony_ci "Failed to set DBBRSTN %c, err %#x\n", 95562306a36Sopenharmony_ci buf[0], err); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ciexit: 95962306a36Sopenharmony_ci return ret; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(chip_id); 96362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(switch_off_status); 96462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(turn_on_status); 96562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(turn_on_status_2); 96662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(dbbrstn); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic struct attribute *ab8500_sysfs_entries[] = { 96962306a36Sopenharmony_ci &dev_attr_chip_id.attr, 97062306a36Sopenharmony_ci &dev_attr_switch_off_status.attr, 97162306a36Sopenharmony_ci &dev_attr_turn_on_status.attr, 97262306a36Sopenharmony_ci NULL, 97362306a36Sopenharmony_ci}; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic struct attribute *ab8505_sysfs_entries[] = { 97662306a36Sopenharmony_ci &dev_attr_turn_on_status_2.attr, 97762306a36Sopenharmony_ci NULL, 97862306a36Sopenharmony_ci}; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic struct attribute *ab9540_sysfs_entries[] = { 98162306a36Sopenharmony_ci &dev_attr_chip_id.attr, 98262306a36Sopenharmony_ci &dev_attr_switch_off_status.attr, 98362306a36Sopenharmony_ci &dev_attr_turn_on_status.attr, 98462306a36Sopenharmony_ci &dev_attr_dbbrstn.attr, 98562306a36Sopenharmony_ci NULL, 98662306a36Sopenharmony_ci}; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic const struct attribute_group ab8500_attr_group = { 98962306a36Sopenharmony_ci .attrs = ab8500_sysfs_entries, 99062306a36Sopenharmony_ci}; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic const struct attribute_group ab8505_attr_group = { 99362306a36Sopenharmony_ci .attrs = ab8505_sysfs_entries, 99462306a36Sopenharmony_ci}; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic const struct attribute_group ab9540_attr_group = { 99762306a36Sopenharmony_ci .attrs = ab9540_sysfs_entries, 99862306a36Sopenharmony_ci}; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic int ab8500_probe(struct platform_device *pdev) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci static const char * const switch_off_status[] = { 100362306a36Sopenharmony_ci "Swoff bit programming", 100462306a36Sopenharmony_ci "Thermal protection activation", 100562306a36Sopenharmony_ci "Vbat lower then BattOk falling threshold", 100662306a36Sopenharmony_ci "Watchdog expired", 100762306a36Sopenharmony_ci "Non presence of 32kHz clock", 100862306a36Sopenharmony_ci "Battery level lower than power on reset threshold", 100962306a36Sopenharmony_ci "Power on key 1 pressed longer than 10 seconds", 101062306a36Sopenharmony_ci "DB8500 thermal shutdown"}; 101162306a36Sopenharmony_ci static const char * const turn_on_status[] = { 101262306a36Sopenharmony_ci "Battery rising (Vbat)", 101362306a36Sopenharmony_ci "Power On Key 1 dbF", 101462306a36Sopenharmony_ci "Power On Key 2 dbF", 101562306a36Sopenharmony_ci "RTC Alarm", 101662306a36Sopenharmony_ci "Main Charger Detect", 101762306a36Sopenharmony_ci "Vbus Detect (USB)", 101862306a36Sopenharmony_ci "USB ID Detect", 101962306a36Sopenharmony_ci "UART Factory Mode Detect"}; 102062306a36Sopenharmony_ci const struct platform_device_id *platid = platform_get_device_id(pdev); 102162306a36Sopenharmony_ci enum ab8500_version version = AB8500_VERSION_UNDEFINED; 102262306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 102362306a36Sopenharmony_ci struct ab8500 *ab8500; 102462306a36Sopenharmony_ci int ret; 102562306a36Sopenharmony_ci int i; 102662306a36Sopenharmony_ci int irq; 102762306a36Sopenharmony_ci u8 value; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 103062306a36Sopenharmony_ci if (!ab8500) 103162306a36Sopenharmony_ci return -ENOMEM; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci ab8500->dev = &pdev->dev; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 103662306a36Sopenharmony_ci if (irq < 0) 103762306a36Sopenharmony_ci return irq; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci ab8500->irq = irq; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ab8500->read = ab8500_prcmu_read; 104262306a36Sopenharmony_ci ab8500->write = ab8500_prcmu_write; 104362306a36Sopenharmony_ci ab8500->write_masked = ab8500_prcmu_write_masked; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci mutex_init(&ab8500->lock); 104662306a36Sopenharmony_ci mutex_init(&ab8500->irq_lock); 104762306a36Sopenharmony_ci atomic_set(&ab8500->transfer_ongoing, 0); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci platform_set_drvdata(pdev, ab8500); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (platid) 105262306a36Sopenharmony_ci version = platid->driver_data; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (version != AB8500_VERSION_UNDEFINED) 105562306a36Sopenharmony_ci ab8500->version = version; 105662306a36Sopenharmony_ci else { 105762306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_MISC, 105862306a36Sopenharmony_ci AB8500_IC_NAME_REG, &value); 105962306a36Sopenharmony_ci if (ret < 0) { 106062306a36Sopenharmony_ci dev_err(&pdev->dev, "could not probe HW\n"); 106162306a36Sopenharmony_ci return ret; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci ab8500->version = value; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_MISC, 106862306a36Sopenharmony_ci AB8500_REV_REG, &value); 106962306a36Sopenharmony_ci if (ret < 0) 107062306a36Sopenharmony_ci return ret; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ab8500->chip_id = value; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 107562306a36Sopenharmony_ci ab8500_version_str[ab8500->version], 107662306a36Sopenharmony_ci ab8500->chip_id >> 4, 107762306a36Sopenharmony_ci ab8500->chip_id & 0x0F); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* Configure AB8540 */ 108062306a36Sopenharmony_ci if (is_ab8540(ab8500)) { 108162306a36Sopenharmony_ci ab8500->mask_size = AB8540_NUM_IRQ_REGS; 108262306a36Sopenharmony_ci ab8500->irq_reg_offset = ab8540_irq_regoffset; 108362306a36Sopenharmony_ci ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 108462306a36Sopenharmony_ci } /* Configure AB8500 or AB9540 IRQ */ 108562306a36Sopenharmony_ci else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 108662306a36Sopenharmony_ci ab8500->mask_size = AB9540_NUM_IRQ_REGS; 108762306a36Sopenharmony_ci ab8500->irq_reg_offset = ab9540_irq_regoffset; 108862306a36Sopenharmony_ci ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 108962306a36Sopenharmony_ci } else { 109062306a36Sopenharmony_ci ab8500->mask_size = AB8500_NUM_IRQ_REGS; 109162306a36Sopenharmony_ci ab8500->irq_reg_offset = ab8500_irq_regoffset; 109262306a36Sopenharmony_ci ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 109562306a36Sopenharmony_ci GFP_KERNEL); 109662306a36Sopenharmony_ci if (!ab8500->mask) 109762306a36Sopenharmony_ci return -ENOMEM; 109862306a36Sopenharmony_ci ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 109962306a36Sopenharmony_ci GFP_KERNEL); 110062306a36Sopenharmony_ci if (!ab8500->oldmask) 110162306a36Sopenharmony_ci return -ENOMEM; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* 110462306a36Sopenharmony_ci * ab8500 has switched off due to (SWITCH_OFF_STATUS): 110562306a36Sopenharmony_ci * 0x01 Swoff bit programming 110662306a36Sopenharmony_ci * 0x02 Thermal protection activation 110762306a36Sopenharmony_ci * 0x04 Vbat lower then BattOk falling threshold 110862306a36Sopenharmony_ci * 0x08 Watchdog expired 110962306a36Sopenharmony_ci * 0x10 Non presence of 32kHz clock 111062306a36Sopenharmony_ci * 0x20 Battery level lower than power on reset threshold 111162306a36Sopenharmony_ci * 0x40 Power on key 1 pressed longer than 10 seconds 111262306a36Sopenharmony_ci * 0x80 DB8500 thermal shutdown 111362306a36Sopenharmony_ci */ 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_RTC, 111662306a36Sopenharmony_ci AB8500_SWITCH_OFF_STATUS, &value); 111762306a36Sopenharmony_ci if (ret < 0) 111862306a36Sopenharmony_ci return ret; 111962306a36Sopenharmony_ci dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (value) { 112262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 112362306a36Sopenharmony_ci if (value & 1) 112462306a36Sopenharmony_ci pr_cont(" \"%s\"", switch_off_status[i]); 112562306a36Sopenharmony_ci value = value >> 1; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci pr_cont("\n"); 112962306a36Sopenharmony_ci } else { 113062306a36Sopenharmony_ci pr_cont(" None\n"); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 113362306a36Sopenharmony_ci AB8500_TURN_ON_STATUS, &value); 113462306a36Sopenharmony_ci if (ret < 0) 113562306a36Sopenharmony_ci return ret; 113662306a36Sopenharmony_ci dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (value) { 113962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 114062306a36Sopenharmony_ci if (value & 1) 114162306a36Sopenharmony_ci pr_cont("\"%s\" ", turn_on_status[i]); 114262306a36Sopenharmony_ci value = value >> 1; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci pr_cont("\n"); 114562306a36Sopenharmony_ci } else { 114662306a36Sopenharmony_ci pr_cont("None\n"); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (is_ab9540(ab8500)) { 115062306a36Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_CHARGER, 115162306a36Sopenharmony_ci AB8500_CH_USBCH_STAT1_REG, &value); 115262306a36Sopenharmony_ci if (ret < 0) 115362306a36Sopenharmony_ci return ret; 115462306a36Sopenharmony_ci if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 115562306a36Sopenharmony_ci ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 115662306a36Sopenharmony_ci AB8500_VBUS_DET); 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Clear and mask all interrupts */ 116062306a36Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) { 116162306a36Sopenharmony_ci /* 116262306a36Sopenharmony_ci * Interrupt register 12 doesn't exist prior to AB8500 version 116362306a36Sopenharmony_ci * 2.0 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci if (ab8500->irq_reg_offset[i] == 11 && 116662306a36Sopenharmony_ci is_ab8500_1p1_or_earlier(ab8500)) 116762306a36Sopenharmony_ci continue; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (ab8500->irq_reg_offset[i] < 0) 117062306a36Sopenharmony_ci continue; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci get_register_interruptible(ab8500, AB8500_INTERRUPT, 117362306a36Sopenharmony_ci AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 117462306a36Sopenharmony_ci &value); 117562306a36Sopenharmony_ci set_register_interruptible(ab8500, AB8500_INTERRUPT, 117662306a36Sopenharmony_ci AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 118062306a36Sopenharmony_ci if (ret) 118162306a36Sopenharmony_ci return ret; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) 118462306a36Sopenharmony_ci ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci ret = ab8500_irq_init(ab8500, np); 118762306a36Sopenharmony_ci if (ret) 118862306a36Sopenharmony_ci return ret; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 119162306a36Sopenharmony_ci ab8500_hierarchical_irq, 119262306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_NO_SUSPEND, 119362306a36Sopenharmony_ci "ab8500", ab8500); 119462306a36Sopenharmony_ci if (ret) 119562306a36Sopenharmony_ci return ret; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (is_ab9540(ab8500)) 119862306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 119962306a36Sopenharmony_ci ARRAY_SIZE(ab9540_devs), NULL, 120062306a36Sopenharmony_ci 0, ab8500->domain); 120162306a36Sopenharmony_ci else if (is_ab8540(ab8500)) { 120262306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 120362306a36Sopenharmony_ci ARRAY_SIZE(ab8540_devs), NULL, 120462306a36Sopenharmony_ci 0, ab8500->domain); 120562306a36Sopenharmony_ci if (ret) 120662306a36Sopenharmony_ci return ret; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (is_ab8540_1p2_or_earlier(ab8500)) 120962306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 121062306a36Sopenharmony_ci ARRAY_SIZE(ab8540_cut1_devs), NULL, 121162306a36Sopenharmony_ci 0, ab8500->domain); 121262306a36Sopenharmony_ci else /* ab8540 >= cut2 */ 121362306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 121462306a36Sopenharmony_ci ARRAY_SIZE(ab8540_cut2_devs), NULL, 121562306a36Sopenharmony_ci 0, ab8500->domain); 121662306a36Sopenharmony_ci } else if (is_ab8505(ab8500)) 121762306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 121862306a36Sopenharmony_ci ARRAY_SIZE(ab8505_devs), NULL, 121962306a36Sopenharmony_ci 0, ab8500->domain); 122062306a36Sopenharmony_ci else 122162306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 122262306a36Sopenharmony_ci ARRAY_SIZE(ab8500_devs), NULL, 122362306a36Sopenharmony_ci 0, ab8500->domain); 122462306a36Sopenharmony_ci if (ret) 122562306a36Sopenharmony_ci return ret; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* Add battery management devices */ 122862306a36Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 122962306a36Sopenharmony_ci ARRAY_SIZE(ab8500_bm_devs), NULL, 123062306a36Sopenharmony_ci 0, ab8500->domain); 123162306a36Sopenharmony_ci if (ret) 123262306a36Sopenharmony_ci dev_err(ab8500->dev, "error adding bm devices\n"); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 123562306a36Sopenharmony_ci ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 123662306a36Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 123762306a36Sopenharmony_ci &ab9540_attr_group); 123862306a36Sopenharmony_ci else 123962306a36Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 124062306a36Sopenharmony_ci &ab8500_attr_group); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 124362306a36Sopenharmony_ci ab8500->chip_id >= AB8500_CUT2P0) 124462306a36Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 124562306a36Sopenharmony_ci &ab8505_attr_group); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (ret) 124862306a36Sopenharmony_ci dev_err(ab8500->dev, "error creating sysfs entries\n"); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci return ret; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic const struct platform_device_id ab8500_id[] = { 125462306a36Sopenharmony_ci { "ab8500-core", AB8500_VERSION_AB8500 }, 125562306a36Sopenharmony_ci { "ab8505-core", AB8500_VERSION_AB8505 }, 125662306a36Sopenharmony_ci { "ab9540-i2c", AB8500_VERSION_AB9540 }, 125762306a36Sopenharmony_ci { "ab8540-i2c", AB8500_VERSION_AB8540 }, 125862306a36Sopenharmony_ci { } 125962306a36Sopenharmony_ci}; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic struct platform_driver ab8500_core_driver = { 126262306a36Sopenharmony_ci .driver = { 126362306a36Sopenharmony_ci .name = "ab8500-core", 126462306a36Sopenharmony_ci .suppress_bind_attrs = true, 126562306a36Sopenharmony_ci }, 126662306a36Sopenharmony_ci .probe = ab8500_probe, 126762306a36Sopenharmony_ci .id_table = ab8500_id, 126862306a36Sopenharmony_ci}; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic int __init ab8500_core_init(void) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci return platform_driver_register(&ab8500_core_driver); 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_cicore_initcall(ab8500_core_init); 1275