1a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo/* 2a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * max8907.c - mfd driver for MAX8907 3a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * 4a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> 5a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved. 6a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * 7a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * This program is free software; you can redistribute it and/or modify 8a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * it under the terms of the GNU General Public License version 2 as 9a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo * published by the Free Software Foundation. 10a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo */ 11a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 12a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/err.h> 13a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/i2c.h> 14a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/init.h> 15a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/interrupt.h> 16a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/irq.h> 17a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/mfd/core.h> 18a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/mfd/max8907.h> 19a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/module.h> 20e4081da476e5e741c4e469a0f8470e9f4169794eSachin Kamat#include <linux/of.h> 21a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/of_device.h> 22a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/regmap.h> 23a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#include <linux/slab.h> 24a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 257c0517b1716bc1aa873064290401a8ce2fbabc32Geert Uytterhoevenstatic const struct mfd_cell max8907_cells[] = { 26a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .name = "max8907-regulator", }, 27a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .name = "max8907-rtc", }, 28a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 29a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 30a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg) 31a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 32a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo switch (reg) { 33a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_ON_OFF_IRQ1: 34a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_ON_OFF_STAT: 35a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_ON_OFF_IRQ2: 36a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_CHG_IRQ1: 37a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_CHG_IRQ2: 38a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_CHG_STAT: 39a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 40a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo default: 41a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return false; 42a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 43a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 44a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 45a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg) 46a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 47a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo switch (reg) { 48a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_ON_OFF_IRQ1: 49a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_ON_OFF_IRQ2: 50a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_CHG_IRQ1: 51a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_CHG_IRQ2: 52a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 53a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo default: 54a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return false; 55a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 56a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 57a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 58a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg) 59a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 60a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return !max8907_gen_is_volatile_reg(dev, reg); 61a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 62a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 63a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_config max8907_regmap_gen_config = { 64a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .reg_bits = 8, 65a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .val_bits = 8, 66a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .volatile_reg = max8907_gen_is_volatile_reg, 67a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .precious_reg = max8907_gen_is_precious_reg, 68a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .writeable_reg = max8907_gen_is_writeable_reg, 69a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .max_register = MAX8907_REG_LDO20VOUT, 70a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .cache_type = REGCACHE_RBTREE, 71a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 72a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 73a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg) 74a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 75a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (reg <= MAX8907_REG_RTC_YEAR2) 76a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 77a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 78a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo switch (reg) { 79a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_RTC_STATUS: 80a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_RTC_IRQ: 81a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 82a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo default: 83a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return false; 84a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 85a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 86a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 87a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg) 88a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 89a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo switch (reg) { 90a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_RTC_IRQ: 91a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 92a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo default: 93a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return false; 94a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 95a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 96a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 97a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg) 98a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 99a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo switch (reg) { 100a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_RTC_STATUS: 101a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo case MAX8907_REG_RTC_IRQ: 102a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return false; 103a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo default: 104a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return true; 105a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 106a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 107a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 108a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_config max8907_regmap_rtc_config = { 109a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .reg_bits = 8, 110a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .val_bits = 8, 111a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .volatile_reg = max8907_rtc_is_volatile_reg, 112a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .precious_reg = max8907_rtc_is_precious_reg, 113a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .writeable_reg = max8907_rtc_is_writeable_reg, 114a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .max_register = MAX8907_REG_MPL_CNTL, 115a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .cache_type = REGCACHE_RBTREE, 116a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 117a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 118a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq max8907_chg_irqs[] = { 119a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 0, }, 120a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 1, }, 121a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 2, }, 122a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 0, }, 123a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 1, }, 124a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 2, }, 125a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 3, }, 126a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 4, }, 127a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 5, }, 128a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 6, }, 129a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 7, }, 130a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 131a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 132a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq_chip max8907_chg_irq_chip = { 133a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .name = "max8907 chg", 134a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .status_base = MAX8907_REG_CHG_IRQ1, 135a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .mask_base = MAX8907_REG_CHG_IRQ1_MASK, 136a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .wake_base = MAX8907_REG_CHG_IRQ1_MASK, 137a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1, 138a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_regs = 2, 139a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .irqs = max8907_chg_irqs, 140a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_irqs = ARRAY_SIZE(max8907_chg_irqs), 141a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 142a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 143a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq max8907_on_off_irqs[] = { 144a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 0, }, 145a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 1, }, 146a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 2, }, 147a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 3, }, 148a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 4, }, 149a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 5, }, 150a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 6, }, 151a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 7, }, 152a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 0, }, 153a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 1, .mask = 1 << 1, }, 154a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 155a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 156a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq_chip max8907_on_off_irq_chip = { 157a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .name = "max8907 on_off", 158a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .status_base = MAX8907_REG_ON_OFF_IRQ1, 159a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK, 160a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1, 161a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_regs = 2, 162a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .irqs = max8907_on_off_irqs, 163a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_irqs = ARRAY_SIZE(max8907_on_off_irqs), 164a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 165a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 166a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq max8907_rtc_irqs[] = { 167a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 2, }, 168a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .reg_offset = 0, .mask = 1 << 3, }, 169a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 170a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 171a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct regmap_irq_chip max8907_rtc_irq_chip = { 172a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .name = "max8907 rtc", 173a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .status_base = MAX8907_REG_RTC_IRQ, 174a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .mask_base = MAX8907_REG_RTC_IRQ_MASK, 175a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_regs = 1, 176a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .irqs = max8907_rtc_irqs, 177a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), 178a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 179a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 1800f471916d4d03503cf6fb696f7c8baf12fec30b9Fengguang Wustatic struct max8907 *max8907_pm_off; 1819582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warrenstatic void max8907_power_off(void) 1829582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren{ 1839582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG, 1849582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF); 1859582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren} 1869582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren 187f791be492f76dea7b0641ed227a60eeb2fa7e255Bill Pembertonstatic int max8907_i2c_probe(struct i2c_client *i2c, 188a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo const struct i2c_device_id *id) 189a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 190a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo struct max8907 *max8907; 191a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo int ret; 1929582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren struct max8907_platform_data *pdata = dev_get_platdata(&i2c->dev); 1939582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren bool pm_off = false; 1949582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren 1959582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren if (pdata) 1969582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren pm_off = pdata->pm_off; 1979582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren else if (i2c->dev.of_node) 1989582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren pm_off = of_property_read_bool(i2c->dev.of_node, 1999582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren "maxim,system-power-controller"); 200a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 201a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); 202a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (!max8907) { 203a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = -ENOMEM; 204a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_alloc_drvdata; 205a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 206a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 207a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907->dev = &i2c->dev; 208a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_set_drvdata(max8907->dev, max8907); 209a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 210a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907->i2c_gen = i2c; 211a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo i2c_set_clientdata(i2c, max8907); 212a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907->regmap_gen = devm_regmap_init_i2c(i2c, 213a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907_regmap_gen_config); 214a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (IS_ERR(max8907->regmap_gen)) { 215a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = PTR_ERR(max8907->regmap_gen); 216a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret); 217a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_regmap_gen; 218a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 219a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 220a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR); 221a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (!max8907->i2c_rtc) { 222a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = -ENOMEM; 223a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_dummy_rtc; 224a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 225a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo i2c_set_clientdata(max8907->i2c_rtc, max8907); 226a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc, 227a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907_regmap_rtc_config); 228a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (IS_ERR(max8907->regmap_rtc)) { 229a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = PTR_ERR(max8907->regmap_rtc); 230a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret); 231a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_regmap_rtc; 232a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 233a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 234a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN); 235a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 236a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, 237a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo IRQF_ONESHOT | IRQF_SHARED, -1, 238a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907_chg_irq_chip, 239a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907->irqc_chg); 240a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (ret != 0) { 241a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret); 242a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_irqc_chg; 243a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 244a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, 245a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo IRQF_ONESHOT | IRQF_SHARED, -1, 246a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907_on_off_irq_chip, 247a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907->irqc_on_off); 248a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (ret != 0) { 249a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret); 250a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_irqc_on_off; 251a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 252a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq, 253a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo IRQF_ONESHOT | IRQF_SHARED, -1, 254a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907_rtc_irq_chip, 255a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo &max8907->irqc_rtc); 256a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (ret != 0) { 257a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret); 258a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_irqc_rtc; 259a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 260a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 261a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo enable_irq(max8907->i2c_gen->irq); 262a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 263a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = mfd_add_devices(max8907->dev, -1, max8907_cells, 264a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ARRAY_SIZE(max8907_cells), NULL, 0, NULL); 265a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (ret != 0) { 266a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret); 267a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo goto err_add_devices; 268a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo } 269a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 2709582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren if (pm_off && !pm_power_off) { 2719582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren max8907_pm_off = max8907; 2729582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren pm_power_off = max8907_power_off; 2739582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren } 2749582fdcb6fcf1b596a83b161a2ea886272d2a62fStephen Warren 275a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return 0; 276a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 277a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_add_devices: 278a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); 279a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_irqc_rtc: 280a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); 281a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_irqc_on_off: 282a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); 283a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_irqc_chg: 284a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_regmap_rtc: 285a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo i2c_unregister_device(max8907->i2c_rtc); 286a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_dummy_rtc: 287a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_regmap_gen: 288a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yooerr_alloc_drvdata: 289a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return ret; 290a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 291a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 2924740f73fe5388ab5d22d552d2a0dacc62418a70cBill Pembertonstatic int max8907_i2c_remove(struct i2c_client *i2c) 293a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 294a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo struct max8907 *max8907 = i2c_get_clientdata(i2c); 295a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 296a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo mfd_remove_devices(max8907->dev); 297a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 298a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); 299a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); 300a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); 301a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 302a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo i2c_unregister_device(max8907->i2c_rtc); 303a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 304a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return 0; 305a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 306a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 307a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#ifdef CONFIG_OF 308488e90032064fa6fcd34d45400a9e45f58668bbcKrzysztof Kozlowskistatic const struct of_device_id max8907_of_match[] = { 309a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { .compatible = "maxim,max8907" }, 310a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo { }, 311a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 312a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh YooMODULE_DEVICE_TABLE(of, max8907_of_match); 313a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo#endif 314a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 315a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic const struct i2c_device_id max8907_i2c_id[] = { 316a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo {"max8907", 0}, 317a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo {} 318a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 319a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh YooMODULE_DEVICE_TABLE(i2c, max8907_i2c_id); 320a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 321a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic struct i2c_driver max8907_i2c_driver = { 322a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .driver = { 323a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .name = "max8907", 324a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .owner = THIS_MODULE, 325a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .of_match_table = of_match_ptr(max8907_of_match), 326a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo }, 327a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .probe = max8907_i2c_probe, 328a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .remove = max8907_i2c_remove, 329a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo .id_table = max8907_i2c_id, 330a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo}; 331a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 332a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic int __init max8907_i2c_init(void) 333a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 334a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo int ret = -ENODEV; 335a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 336a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo ret = i2c_add_driver(&max8907_i2c_driver); 337a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo if (ret != 0) 338a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo pr_err("Failed to register I2C driver: %d\n", ret); 339a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 340a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo return ret; 341a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 342a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoosubsys_initcall(max8907_i2c_init); 343a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 344a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoostatic void __exit max8907_i2c_exit(void) 345a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo{ 346a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo i2c_del_driver(&max8907_i2c_driver); 347a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo} 348a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoomodule_exit(max8907_i2c_exit); 349a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh Yoo 350a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh YooMODULE_DESCRIPTION("MAX8907 multi-function core driver"); 351a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh YooMODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); 352a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6Gyungoh YooMODULE_LICENSE("GPL v2"); 353