18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 118c2ecf20Sopenharmony_ci#include <linux/irq.h> 128c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/ssbi.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_BASE 0x1BB 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0) 258c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1) 268c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2) 278c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3) 288c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4) 298c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5) 308c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6) 318c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7) 328c2ecf20Sopenharmony_ci#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define PM8821_SSBI_REG_ADDR_IRQ_BASE 0x100 358c2ecf20Sopenharmony_ci#define PM8821_SSBI_REG_ADDR_IRQ_MASTER0 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0x30) 368c2ecf20Sopenharmony_ci#define PM8821_SSBI_REG_ADDR_IRQ_MASTER1 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0xb0) 378c2ecf20Sopenharmony_ci#define PM8821_SSBI_REG(m, b, offset) \ 388c2ecf20Sopenharmony_ci ((m == 0) ? \ 398c2ecf20Sopenharmony_ci (PM8821_SSBI_REG_ADDR_IRQ_MASTER0 + b + offset) : \ 408c2ecf20Sopenharmony_ci (PM8821_SSBI_REG_ADDR_IRQ_MASTER1 + b + offset)) 418c2ecf20Sopenharmony_ci#define PM8821_SSBI_ADDR_IRQ_ROOT(m, b) PM8821_SSBI_REG(m, b, 0x0) 428c2ecf20Sopenharmony_ci#define PM8821_SSBI_ADDR_IRQ_CLEAR(m, b) PM8821_SSBI_REG(m, b, 0x01) 438c2ecf20Sopenharmony_ci#define PM8821_SSBI_ADDR_IRQ_MASK(m, b) PM8821_SSBI_REG(m, b, 0x08) 448c2ecf20Sopenharmony_ci#define PM8821_SSBI_ADDR_IRQ_RT_STATUS(m, b) PM8821_SSBI_REG(m, b, 0x0f) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define PM8821_BLOCKS_PER_MASTER 7 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define PM_IRQF_LVL_SEL 0x01 /* level select */ 498c2ecf20Sopenharmony_ci#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */ 508c2ecf20Sopenharmony_ci#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */ 518c2ecf20Sopenharmony_ci#define PM_IRQF_CLR 0x08 /* clear interrupt */ 528c2ecf20Sopenharmony_ci#define PM_IRQF_BITS_MASK 0x70 538c2ecf20Sopenharmony_ci#define PM_IRQF_BITS_SHIFT 4 548c2ecf20Sopenharmony_ci#define PM_IRQF_WRITE 0x80 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \ 578c2ecf20Sopenharmony_ci PM_IRQF_MASK_RE) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define REG_HWREV 0x002 /* PMIC4 revision */ 608c2ecf20Sopenharmony_ci#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define PM8XXX_NR_IRQS 256 638c2ecf20Sopenharmony_ci#define PM8821_NR_IRQS 112 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct pm_irq_data { 668c2ecf20Sopenharmony_ci int num_irqs; 678c2ecf20Sopenharmony_ci struct irq_chip *irq_chip; 688c2ecf20Sopenharmony_ci void (*irq_handler)(struct irq_desc *desc); 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct pm_irq_chip { 728c2ecf20Sopenharmony_ci struct regmap *regmap; 738c2ecf20Sopenharmony_ci spinlock_t pm_irq_lock; 748c2ecf20Sopenharmony_ci struct irq_domain *irqdomain; 758c2ecf20Sopenharmony_ci unsigned int num_blocks; 768c2ecf20Sopenharmony_ci unsigned int num_masters; 778c2ecf20Sopenharmony_ci const struct pm_irq_data *pm_irq_data; 788c2ecf20Sopenharmony_ci /* MUST BE AT THE END OF THIS STRUCT */ 798c2ecf20Sopenharmony_ci u8 config[]; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, 838c2ecf20Sopenharmony_ci unsigned int *ip) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci int rc; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci spin_lock(&chip->pm_irq_lock); 888c2ecf20Sopenharmony_ci rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); 898c2ecf20Sopenharmony_ci if (rc) { 908c2ecf20Sopenharmony_ci pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); 918c2ecf20Sopenharmony_ci goto bail; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_IT_STATUS, ip); 958c2ecf20Sopenharmony_ci if (rc) 968c2ecf20Sopenharmony_ci pr_err("Failed Reading Status rc=%d\n", rc); 978c2ecf20Sopenharmony_cibail: 988c2ecf20Sopenharmony_ci spin_unlock(&chip->pm_irq_lock); 998c2ecf20Sopenharmony_ci return rc; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int 1038c2ecf20Sopenharmony_cipm8xxx_config_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int cp) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int rc; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci spin_lock(&chip->pm_irq_lock); 1088c2ecf20Sopenharmony_ci rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); 1098c2ecf20Sopenharmony_ci if (rc) { 1108c2ecf20Sopenharmony_ci pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); 1118c2ecf20Sopenharmony_ci goto bail; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci cp |= PM_IRQF_WRITE; 1158c2ecf20Sopenharmony_ci rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_CONFIG, cp); 1168c2ecf20Sopenharmony_ci if (rc) 1178c2ecf20Sopenharmony_ci pr_err("Failed Configuring IRQ rc=%d\n", rc); 1188c2ecf20Sopenharmony_cibail: 1198c2ecf20Sopenharmony_ci spin_unlock(&chip->pm_irq_lock); 1208c2ecf20Sopenharmony_ci return rc; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int pmirq, irq, i, ret = 0; 1268c2ecf20Sopenharmony_ci unsigned int bits; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ret = pm8xxx_read_block_irq(chip, block, &bits); 1298c2ecf20Sopenharmony_ci if (ret) { 1308c2ecf20Sopenharmony_ci pr_err("Failed reading %d block ret=%d", block, ret); 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci if (!bits) { 1348c2ecf20Sopenharmony_ci pr_err("block bit set in master but no irqs: %d", block); 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Check IRQ bits */ 1398c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 1408c2ecf20Sopenharmony_ci if (bits & (1 << i)) { 1418c2ecf20Sopenharmony_ci pmirq = block * 8 + i; 1428c2ecf20Sopenharmony_ci irq = irq_find_mapping(chip->irqdomain, pmirq); 1438c2ecf20Sopenharmony_ci generic_handle_irq(irq); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci unsigned int blockbits; 1528c2ecf20Sopenharmony_ci int block_number, i, ret = 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_M_STATUS1 + master, 1558c2ecf20Sopenharmony_ci &blockbits); 1568c2ecf20Sopenharmony_ci if (ret) { 1578c2ecf20Sopenharmony_ci pr_err("Failed to read master %d ret=%d\n", master, ret); 1588c2ecf20Sopenharmony_ci return ret; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (!blockbits) { 1618c2ecf20Sopenharmony_ci pr_err("master bit set in root but no blocks: %d", master); 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 1668c2ecf20Sopenharmony_ci if (blockbits & (1 << i)) { 1678c2ecf20Sopenharmony_ci block_number = master * 8 + i; /* block # */ 1688c2ecf20Sopenharmony_ci ret |= pm8xxx_irq_block_handler(chip, block_number); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci return ret; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void pm8xxx_irq_handler(struct irq_desc *desc) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_desc_get_handler_data(desc); 1768c2ecf20Sopenharmony_ci struct irq_chip *irq_chip = irq_desc_get_chip(desc); 1778c2ecf20Sopenharmony_ci unsigned int root; 1788c2ecf20Sopenharmony_ci int i, ret, masters = 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci chained_irq_enter(irq_chip, desc); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_ROOT, &root); 1838c2ecf20Sopenharmony_ci if (ret) { 1848c2ecf20Sopenharmony_ci pr_err("Can't read root status ret=%d\n", ret); 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* on pm8xxx series masters start from bit 1 of the root */ 1898c2ecf20Sopenharmony_ci masters = root >> 1; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Read allowed masters for blocks. */ 1928c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_masters; i++) 1938c2ecf20Sopenharmony_ci if (masters & (1 << i)) 1948c2ecf20Sopenharmony_ci pm8xxx_irq_master_handler(chip, i); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci chained_irq_exit(irq_chip, desc); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void pm8821_irq_block_handler(struct pm_irq_chip *chip, 2008c2ecf20Sopenharmony_ci int master, int block) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int pmirq, irq, i, ret; 2038c2ecf20Sopenharmony_ci unsigned int bits; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, 2068c2ecf20Sopenharmony_ci PM8821_SSBI_ADDR_IRQ_ROOT(master, block), &bits); 2078c2ecf20Sopenharmony_ci if (ret) { 2088c2ecf20Sopenharmony_ci pr_err("Reading block %d failed ret=%d", block, ret); 2098c2ecf20Sopenharmony_ci return; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Convert block offset to global block number */ 2138c2ecf20Sopenharmony_ci block += (master * PM8821_BLOCKS_PER_MASTER) - 1; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Check IRQ bits */ 2168c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 2178c2ecf20Sopenharmony_ci if (bits & BIT(i)) { 2188c2ecf20Sopenharmony_ci pmirq = block * 8 + i; 2198c2ecf20Sopenharmony_ci irq = irq_find_mapping(chip->irqdomain, pmirq); 2208c2ecf20Sopenharmony_ci generic_handle_irq(irq); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline void pm8821_irq_master_handler(struct pm_irq_chip *chip, 2268c2ecf20Sopenharmony_ci int master, u8 master_val) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int block; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (block = 1; block < 8; block++) 2318c2ecf20Sopenharmony_ci if (master_val & BIT(block)) 2328c2ecf20Sopenharmony_ci pm8821_irq_block_handler(chip, master, block); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void pm8821_irq_handler(struct irq_desc *desc) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_desc_get_handler_data(desc); 2388c2ecf20Sopenharmony_ci struct irq_chip *irq_chip = irq_desc_get_chip(desc); 2398c2ecf20Sopenharmony_ci unsigned int master; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci chained_irq_enter(irq_chip, desc); 2438c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, 2448c2ecf20Sopenharmony_ci PM8821_SSBI_REG_ADDR_IRQ_MASTER0, &master); 2458c2ecf20Sopenharmony_ci if (ret) { 2468c2ecf20Sopenharmony_ci pr_err("Failed to read master 0 ret=%d\n", ret); 2478c2ecf20Sopenharmony_ci goto done; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* bits 1 through 7 marks the first 7 blocks in master 0 */ 2518c2ecf20Sopenharmony_ci if (master & GENMASK(7, 1)) 2528c2ecf20Sopenharmony_ci pm8821_irq_master_handler(chip, 0, master); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* bit 0 marks if master 1 contains any bits */ 2558c2ecf20Sopenharmony_ci if (!(master & BIT(0))) 2568c2ecf20Sopenharmony_ci goto done; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, 2598c2ecf20Sopenharmony_ci PM8821_SSBI_REG_ADDR_IRQ_MASTER1, &master); 2608c2ecf20Sopenharmony_ci if (ret) { 2618c2ecf20Sopenharmony_ci pr_err("Failed to read master 1 ret=%d\n", ret); 2628c2ecf20Sopenharmony_ci goto done; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci pm8821_irq_master_handler(chip, 1, master); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cidone: 2688c2ecf20Sopenharmony_ci chained_irq_exit(irq_chip, desc); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void pm8xxx_irq_mask_ack(struct irq_data *d) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 2748c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 2758c2ecf20Sopenharmony_ci u8 block, config; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci block = pmirq / 8; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR; 2808c2ecf20Sopenharmony_ci pm8xxx_config_irq(chip, block, config); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void pm8xxx_irq_unmask(struct irq_data *d) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 2868c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 2878c2ecf20Sopenharmony_ci u8 block, config; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci block = pmirq / 8; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci config = chip->config[pmirq]; 2928c2ecf20Sopenharmony_ci pm8xxx_config_irq(chip, block, config); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 2988c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 2998c2ecf20Sopenharmony_ci int irq_bit; 3008c2ecf20Sopenharmony_ci u8 block, config; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci block = pmirq / 8; 3038c2ecf20Sopenharmony_ci irq_bit = pmirq % 8; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT) 3068c2ecf20Sopenharmony_ci | PM_IRQF_MASK_ALL; 3078c2ecf20Sopenharmony_ci if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { 3088c2ecf20Sopenharmony_ci if (flow_type & IRQF_TRIGGER_RISING) 3098c2ecf20Sopenharmony_ci chip->config[pmirq] &= ~PM_IRQF_MASK_RE; 3108c2ecf20Sopenharmony_ci if (flow_type & IRQF_TRIGGER_FALLING) 3118c2ecf20Sopenharmony_ci chip->config[pmirq] &= ~PM_IRQF_MASK_FE; 3128c2ecf20Sopenharmony_ci } else { 3138c2ecf20Sopenharmony_ci chip->config[pmirq] |= PM_IRQF_LVL_SEL; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (flow_type & IRQF_TRIGGER_HIGH) 3168c2ecf20Sopenharmony_ci chip->config[pmirq] &= ~PM_IRQF_MASK_RE; 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci chip->config[pmirq] &= ~PM_IRQF_MASK_FE; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci config = chip->config[pmirq] | PM_IRQF_CLR; 3228c2ecf20Sopenharmony_ci return pm8xxx_config_irq(chip, block, config); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int pm8xxx_irq_get_irqchip_state(struct irq_data *d, 3268c2ecf20Sopenharmony_ci enum irqchip_irq_state which, 3278c2ecf20Sopenharmony_ci bool *state) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 3308c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 3318c2ecf20Sopenharmony_ci unsigned int bits; 3328c2ecf20Sopenharmony_ci int irq_bit; 3338c2ecf20Sopenharmony_ci u8 block; 3348c2ecf20Sopenharmony_ci int rc; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (which != IRQCHIP_STATE_LINE_LEVEL) 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci block = pmirq / 8; 3408c2ecf20Sopenharmony_ci irq_bit = pmirq % 8; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci spin_lock(&chip->pm_irq_lock); 3438c2ecf20Sopenharmony_ci rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block); 3448c2ecf20Sopenharmony_ci if (rc) { 3458c2ecf20Sopenharmony_ci pr_err("Failed Selecting Block %d rc=%d\n", block, rc); 3468c2ecf20Sopenharmony_ci goto bail; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits); 3508c2ecf20Sopenharmony_ci if (rc) { 3518c2ecf20Sopenharmony_ci pr_err("Failed Reading Status rc=%d\n", rc); 3528c2ecf20Sopenharmony_ci goto bail; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci *state = !!(bits & BIT(irq_bit)); 3568c2ecf20Sopenharmony_cibail: 3578c2ecf20Sopenharmony_ci spin_unlock(&chip->pm_irq_lock); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return rc; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct irq_chip pm8xxx_irq_chip = { 3638c2ecf20Sopenharmony_ci .name = "pm8xxx", 3648c2ecf20Sopenharmony_ci .irq_mask_ack = pm8xxx_irq_mask_ack, 3658c2ecf20Sopenharmony_ci .irq_unmask = pm8xxx_irq_unmask, 3668c2ecf20Sopenharmony_ci .irq_set_type = pm8xxx_irq_set_type, 3678c2ecf20Sopenharmony_ci .irq_get_irqchip_state = pm8xxx_irq_get_irqchip_state, 3688c2ecf20Sopenharmony_ci .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, 3728c2ecf20Sopenharmony_ci struct irq_domain *domain, unsigned int irq, 3738c2ecf20Sopenharmony_ci irq_hw_number_t hwirq, unsigned int type) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, 3768c2ecf20Sopenharmony_ci chip, handle_level_irq, NULL, NULL); 3778c2ecf20Sopenharmony_ci irq_set_noprobe(irq); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 3818c2ecf20Sopenharmony_ci unsigned int nr_irqs, void *data) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = domain->host_data; 3848c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec = data; 3858c2ecf20Sopenharmony_ci irq_hw_number_t hwirq; 3868c2ecf20Sopenharmony_ci unsigned int type; 3878c2ecf20Sopenharmony_ci int ret, i; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); 3908c2ecf20Sopenharmony_ci if (ret) 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci for (i = 0; i < nr_irqs; i++) 3948c2ecf20Sopenharmony_ci pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic const struct irq_domain_ops pm8xxx_irq_domain_ops = { 4008c2ecf20Sopenharmony_ci .alloc = pm8xxx_irq_domain_alloc, 4018c2ecf20Sopenharmony_ci .free = irq_domain_free_irqs_common, 4028c2ecf20Sopenharmony_ci .translate = irq_domain_translate_twocell, 4038c2ecf20Sopenharmony_ci}; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void pm8821_irq_mask_ack(struct irq_data *d) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 4088c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 4098c2ecf20Sopenharmony_ci u8 block, master; 4108c2ecf20Sopenharmony_ci int irq_bit, rc; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci block = pmirq / 8; 4138c2ecf20Sopenharmony_ci master = block / PM8821_BLOCKS_PER_MASTER; 4148c2ecf20Sopenharmony_ci irq_bit = pmirq % 8; 4158c2ecf20Sopenharmony_ci block %= PM8821_BLOCKS_PER_MASTER; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci rc = regmap_update_bits(chip->regmap, 4188c2ecf20Sopenharmony_ci PM8821_SSBI_ADDR_IRQ_MASK(master, block), 4198c2ecf20Sopenharmony_ci BIT(irq_bit), BIT(irq_bit)); 4208c2ecf20Sopenharmony_ci if (rc) { 4218c2ecf20Sopenharmony_ci pr_err("Failed to mask IRQ:%d rc=%d\n", pmirq, rc); 4228c2ecf20Sopenharmony_ci return; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci rc = regmap_update_bits(chip->regmap, 4268c2ecf20Sopenharmony_ci PM8821_SSBI_ADDR_IRQ_CLEAR(master, block), 4278c2ecf20Sopenharmony_ci BIT(irq_bit), BIT(irq_bit)); 4288c2ecf20Sopenharmony_ci if (rc) 4298c2ecf20Sopenharmony_ci pr_err("Failed to CLEAR IRQ:%d rc=%d\n", pmirq, rc); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void pm8821_irq_unmask(struct irq_data *d) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 4358c2ecf20Sopenharmony_ci unsigned int pmirq = irqd_to_hwirq(d); 4368c2ecf20Sopenharmony_ci int irq_bit, rc; 4378c2ecf20Sopenharmony_ci u8 block, master; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci block = pmirq / 8; 4408c2ecf20Sopenharmony_ci master = block / PM8821_BLOCKS_PER_MASTER; 4418c2ecf20Sopenharmony_ci irq_bit = pmirq % 8; 4428c2ecf20Sopenharmony_ci block %= PM8821_BLOCKS_PER_MASTER; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci rc = regmap_update_bits(chip->regmap, 4458c2ecf20Sopenharmony_ci PM8821_SSBI_ADDR_IRQ_MASK(master, block), 4468c2ecf20Sopenharmony_ci BIT(irq_bit), ~BIT(irq_bit)); 4478c2ecf20Sopenharmony_ci if (rc) 4488c2ecf20Sopenharmony_ci pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int pm8821_irq_get_irqchip_state(struct irq_data *d, 4538c2ecf20Sopenharmony_ci enum irqchip_irq_state which, 4548c2ecf20Sopenharmony_ci bool *state) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 4578c2ecf20Sopenharmony_ci int rc, pmirq = irqd_to_hwirq(d); 4588c2ecf20Sopenharmony_ci u8 block, irq_bit, master; 4598c2ecf20Sopenharmony_ci unsigned int bits; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci block = pmirq / 8; 4628c2ecf20Sopenharmony_ci master = block / PM8821_BLOCKS_PER_MASTER; 4638c2ecf20Sopenharmony_ci irq_bit = pmirq % 8; 4648c2ecf20Sopenharmony_ci block %= PM8821_BLOCKS_PER_MASTER; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci rc = regmap_read(chip->regmap, 4678c2ecf20Sopenharmony_ci PM8821_SSBI_ADDR_IRQ_RT_STATUS(master, block), &bits); 4688c2ecf20Sopenharmony_ci if (rc) { 4698c2ecf20Sopenharmony_ci pr_err("Reading Status of IRQ %d failed rc=%d\n", pmirq, rc); 4708c2ecf20Sopenharmony_ci return rc; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci *state = !!(bits & BIT(irq_bit)); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return rc; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic struct irq_chip pm8821_irq_chip = { 4798c2ecf20Sopenharmony_ci .name = "pm8821", 4808c2ecf20Sopenharmony_ci .irq_mask_ack = pm8821_irq_mask_ack, 4818c2ecf20Sopenharmony_ci .irq_unmask = pm8821_irq_unmask, 4828c2ecf20Sopenharmony_ci .irq_get_irqchip_state = pm8821_irq_get_irqchip_state, 4838c2ecf20Sopenharmony_ci .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, 4848c2ecf20Sopenharmony_ci}; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic const struct regmap_config ssbi_regmap_config = { 4878c2ecf20Sopenharmony_ci .reg_bits = 16, 4888c2ecf20Sopenharmony_ci .val_bits = 8, 4898c2ecf20Sopenharmony_ci .max_register = 0x3ff, 4908c2ecf20Sopenharmony_ci .fast_io = true, 4918c2ecf20Sopenharmony_ci .reg_read = ssbi_reg_read, 4928c2ecf20Sopenharmony_ci .reg_write = ssbi_reg_write 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic const struct pm_irq_data pm8xxx_data = { 4968c2ecf20Sopenharmony_ci .num_irqs = PM8XXX_NR_IRQS, 4978c2ecf20Sopenharmony_ci .irq_chip = &pm8xxx_irq_chip, 4988c2ecf20Sopenharmony_ci .irq_handler = pm8xxx_irq_handler, 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic const struct pm_irq_data pm8821_data = { 5028c2ecf20Sopenharmony_ci .num_irqs = PM8821_NR_IRQS, 5038c2ecf20Sopenharmony_ci .irq_chip = &pm8821_irq_chip, 5048c2ecf20Sopenharmony_ci .irq_handler = pm8821_irq_handler, 5058c2ecf20Sopenharmony_ci}; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic const struct of_device_id pm8xxx_id_table[] = { 5088c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8018", .data = &pm8xxx_data}, 5098c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8058", .data = &pm8xxx_data}, 5108c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8821", .data = &pm8821_data}, 5118c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8921", .data = &pm8xxx_data}, 5128c2ecf20Sopenharmony_ci { } 5138c2ecf20Sopenharmony_ci}; 5148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pm8xxx_id_table); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int pm8xxx_probe(struct platform_device *pdev) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci const struct pm_irq_data *data; 5198c2ecf20Sopenharmony_ci struct regmap *regmap; 5208c2ecf20Sopenharmony_ci int irq, rc; 5218c2ecf20Sopenharmony_ci unsigned int val; 5228c2ecf20Sopenharmony_ci u32 rev; 5238c2ecf20Sopenharmony_ci struct pm_irq_chip *chip; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci data = of_device_get_match_data(&pdev->dev); 5268c2ecf20Sopenharmony_ci if (!data) { 5278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No matching driver data found\n"); 5288c2ecf20Sopenharmony_ci return -EINVAL; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 5328c2ecf20Sopenharmony_ci if (irq < 0) 5338c2ecf20Sopenharmony_ci return irq; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent, 5368c2ecf20Sopenharmony_ci &ssbi_regmap_config); 5378c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) 5388c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* Read PMIC chip revision */ 5418c2ecf20Sopenharmony_ci rc = regmap_read(regmap, REG_HWREV, &val); 5428c2ecf20Sopenharmony_ci if (rc) { 5438c2ecf20Sopenharmony_ci pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc); 5448c2ecf20Sopenharmony_ci return rc; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci pr_info("PMIC revision 1: %02X\n", val); 5478c2ecf20Sopenharmony_ci rev = val; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* Read PMIC chip revision 2 */ 5508c2ecf20Sopenharmony_ci rc = regmap_read(regmap, REG_HWREV_2, &val); 5518c2ecf20Sopenharmony_ci if (rc) { 5528c2ecf20Sopenharmony_ci pr_err("Failed to read hw rev 2 reg %d:rc=%d\n", 5538c2ecf20Sopenharmony_ci REG_HWREV_2, rc); 5548c2ecf20Sopenharmony_ci return rc; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci pr_info("PMIC revision 2: %02X\n", val); 5578c2ecf20Sopenharmony_ci rev |= val << BITS_PER_BYTE; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci chip = devm_kzalloc(&pdev->dev, 5608c2ecf20Sopenharmony_ci struct_size(chip, config, data->num_irqs), 5618c2ecf20Sopenharmony_ci GFP_KERNEL); 5628c2ecf20Sopenharmony_ci if (!chip) 5638c2ecf20Sopenharmony_ci return -ENOMEM; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chip); 5668c2ecf20Sopenharmony_ci chip->regmap = regmap; 5678c2ecf20Sopenharmony_ci chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8); 5688c2ecf20Sopenharmony_ci chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); 5698c2ecf20Sopenharmony_ci chip->pm_irq_data = data; 5708c2ecf20Sopenharmony_ci spin_lock_init(&chip->pm_irq_lock); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, 5738c2ecf20Sopenharmony_ci data->num_irqs, 5748c2ecf20Sopenharmony_ci &pm8xxx_irq_domain_ops, 5758c2ecf20Sopenharmony_ci chip); 5768c2ecf20Sopenharmony_ci if (!chip->irqdomain) 5778c2ecf20Sopenharmony_ci return -ENODEV; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(irq, data->irq_handler, chip); 5808c2ecf20Sopenharmony_ci irq_set_irq_wake(irq, 1); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 5838c2ecf20Sopenharmony_ci if (rc) { 5848c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(irq, NULL, NULL); 5858c2ecf20Sopenharmony_ci irq_domain_remove(chip->irqdomain); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return rc; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int pm8xxx_remove_child(struct device *dev, void *unused) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci platform_device_unregister(to_platform_device(dev)); 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int pm8xxx_remove(struct platform_device *pdev) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci int irq = platform_get_irq(pdev, 0); 6008c2ecf20Sopenharmony_ci struct pm_irq_chip *chip = platform_get_drvdata(pdev); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci device_for_each_child(&pdev->dev, NULL, pm8xxx_remove_child); 6038c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(irq, NULL, NULL); 6048c2ecf20Sopenharmony_ci irq_domain_remove(chip->irqdomain); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic struct platform_driver pm8xxx_driver = { 6108c2ecf20Sopenharmony_ci .probe = pm8xxx_probe, 6118c2ecf20Sopenharmony_ci .remove = pm8xxx_remove, 6128c2ecf20Sopenharmony_ci .driver = { 6138c2ecf20Sopenharmony_ci .name = "pm8xxx-core", 6148c2ecf20Sopenharmony_ci .of_match_table = pm8xxx_id_table, 6158c2ecf20Sopenharmony_ci }, 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int __init pm8xxx_init(void) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci return platform_driver_register(&pm8xxx_driver); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_cisubsys_initcall(pm8xxx_init); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void __exit pm8xxx_exit(void) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci platform_driver_unregister(&pm8xxx_driver); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_cimodule_exit(pm8xxx_exit); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PMIC 8xxx core driver"); 6328c2ecf20Sopenharmony_ciMODULE_VERSION("1.0"); 6338c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pm8xxx-core"); 634