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