Blame view
drivers/mfd/rn5t618.c
6.88 KB
3c910ecbd treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
9bb9e29c7 mfd: Add Ricoh RN... |
2 3 4 5 |
/* * MFD core driver for Ricoh RN5T618 PMIC * * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> |
a99ab50db mfd: rn5t618: Add... |
6 |
* Copyright (C) 2016 Toradex AG |
9bb9e29c7 mfd: Add Ricoh RN... |
7 |
*/ |
a370f60a5 mfd: rn5t618: Reg... |
8 |
#include <linux/delay.h> |
9bb9e29c7 mfd: Add Ricoh RN... |
9 |
#include <linux/i2c.h> |
0c8160451 mfd: rn5t618: Add... |
10 11 |
#include <linux/interrupt.h> #include <linux/irq.h> |
9bb9e29c7 mfd: Add Ricoh RN... |
12 13 14 |
#include <linux/mfd/core.h> #include <linux/mfd/rn5t618.h> #include <linux/module.h> |
a99ab50db mfd: rn5t618: Add... |
15 |
#include <linux/of_device.h> |
bc6167661 mfd: rn5t618: Add... |
16 |
#include <linux/platform_device.h> |
a370f60a5 mfd: rn5t618: Reg... |
17 |
#include <linux/reboot.h> |
9bb9e29c7 mfd: Add Ricoh RN... |
18 19 20 21 22 23 |
#include <linux/regmap.h> static const struct mfd_cell rn5t618_cells[] = { { .name = "rn5t618-regulator" }, { .name = "rn5t618-wdt" }, }; |
bc6167661 mfd: rn5t618: Add... |
24 25 |
static const struct mfd_cell rc5t619_cells[] = { { .name = "rn5t618-adc" }, |
d1264a075 mfd: rn5t618: Add... |
26 |
{ .name = "rn5t618-power" }, |
bc6167661 mfd: rn5t618: Add... |
27 28 29 30 |
{ .name = "rn5t618-regulator" }, { .name = "rc5t619-rtc" }, { .name = "rn5t618-wdt" }, }; |
9bb9e29c7 mfd: Add Ricoh RN... |
31 32 33 34 35 36 |
static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case RN5T618_WATCHDOGCNT: case RN5T618_DCIRQ: case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL: |
2f3dc25c0 mfd: rn5t618: Mar... |
37 |
case RN5T618_ADCCNT3: |
9bb9e29c7 mfd: Add Ricoh RN... |
38 39 40 41 42 |
case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3: case RN5T618_IR_GPR: case RN5T618_IR_GPF: case RN5T618_MON_IOIN: case RN5T618_INTMON: |
11027ce6f mfd: rn5t618: Add... |
43 44 |
case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2: case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR: |
594f1935b mfd: rn5t618: Fix... |
45 46 47 |
case RN5T618_CHGSTATE: case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI: case RN5T618_CONTROL ... RN5T618_CC_AVEREG0: |
9bb9e29c7 mfd: Add Ricoh RN... |
48 49 50 51 52 53 54 55 56 57 58 59 60 |
return true; default: return false; } } static const struct regmap_config rn5t618_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_reg = rn5t618_volatile_reg, .max_register = RN5T618_MAX_REG, .cache_type = REGCACHE_RBTREE, }; |
0c8160451 mfd: rn5t618: Add... |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
static const struct regmap_irq rc5t619_irqs[] = { REGMAP_IRQ_REG(RN5T618_IRQ_SYS, 0, BIT(0)), REGMAP_IRQ_REG(RN5T618_IRQ_DCDC, 0, BIT(1)), REGMAP_IRQ_REG(RN5T618_IRQ_RTC, 0, BIT(2)), REGMAP_IRQ_REG(RN5T618_IRQ_ADC, 0, BIT(3)), REGMAP_IRQ_REG(RN5T618_IRQ_GPIO, 0, BIT(4)), REGMAP_IRQ_REG(RN5T618_IRQ_CHG, 0, BIT(6)), }; static const struct regmap_irq_chip rc5t619_irq_chip = { .name = "rc5t619", .irqs = rc5t619_irqs, .num_irqs = ARRAY_SIZE(rc5t619_irqs), .num_regs = 1, .status_base = RN5T618_INTMON, .mask_base = RN5T618_INTEN, .mask_invert = true, }; |
cf84dc0bb mfd: rn5t618: Mak... |
79 |
static struct i2c_client *rn5t618_pm_power_off; |
a370f60a5 mfd: rn5t618: Reg... |
80 |
static struct notifier_block rn5t618_restart_handler; |
9bb9e29c7 mfd: Add Ricoh RN... |
81 |
|
0c8160451 mfd: rn5t618: Add... |
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
static int rn5t618_irq_init(struct rn5t618 *rn5t618) { const struct regmap_irq_chip *irq_chip = NULL; int ret; if (!rn5t618->irq) return 0; switch (rn5t618->variant) { case RC5T619: irq_chip = &rc5t619_irq_chip; break; default: dev_err(rn5t618->dev, "Currently no IRQ support for variant %d ", (int)rn5t618->variant); return -ENOENT; } ret = devm_regmap_add_irq_chip(rn5t618->dev, rn5t618->regmap, rn5t618->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, irq_chip, &rn5t618->irq_data); if (ret) dev_err(rn5t618->dev, "Failed to register IRQ chip "); return ret; } |
a370f60a5 mfd: rn5t618: Reg... |
111 |
static void rn5t618_trigger_poweroff_sequence(bool repower) |
9bb9e29c7 mfd: Add Ricoh RN... |
112 |
{ |
cf84dc0bb mfd: rn5t618: Mak... |
113 |
int ret; |
9bb9e29c7 mfd: Add Ricoh RN... |
114 |
/* disable automatic repower-on */ |
cf84dc0bb mfd: rn5t618: Mak... |
115 116 117 118 119 120 121 122 123 124 125 126 |
ret = i2c_smbus_read_byte_data(rn5t618_pm_power_off, RN5T618_REPCNT); if (ret < 0) goto err; ret &= ~RN5T618_REPCNT_REPWRON; if (repower) ret |= RN5T618_REPCNT_REPWRON; ret = i2c_smbus_write_byte_data(rn5t618_pm_power_off, RN5T618_REPCNT, (u8)ret); if (ret < 0) goto err; |
9bb9e29c7 mfd: Add Ricoh RN... |
127 |
/* start power-off sequence */ |
cf84dc0bb mfd: rn5t618: Mak... |
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
ret = i2c_smbus_read_byte_data(rn5t618_pm_power_off, RN5T618_SLPCNT); if (ret < 0) goto err; ret |= RN5T618_SLPCNT_SWPWROFF; ret = i2c_smbus_write_byte_data(rn5t618_pm_power_off, RN5T618_SLPCNT, (u8)ret); if (ret < 0) goto err; return; err: dev_alert(&rn5t618_pm_power_off->dev, "Failed to shutdown (err = %d) ", ret); |
9bb9e29c7 mfd: Add Ricoh RN... |
144 |
} |
a370f60a5 mfd: rn5t618: Reg... |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
static void rn5t618_power_off(void) { rn5t618_trigger_poweroff_sequence(false); } static int rn5t618_restart(struct notifier_block *this, unsigned long mode, void *cmd) { rn5t618_trigger_poweroff_sequence(true); /* * Re-power factor detection on PMIC side is not instant. 1ms * proved to be enough time until reset takes effect. */ mdelay(1); return NOTIFY_DONE; } |
a99ab50db mfd: rn5t618: Add... |
163 164 165 |
static const struct of_device_id rn5t618_of_match[] = { { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 }, { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 }, |
c5e589a17 mfd: rn5t618: Add... |
166 |
{ .compatible = "ricoh,rc5t619", .data = (void *)RC5T619 }, |
a99ab50db mfd: rn5t618: Add... |
167 168 169 |
{ } }; MODULE_DEVICE_TABLE(of, rn5t618_of_match); |
7858658cd mfd: rn5t618: Cle... |
170 |
static int rn5t618_i2c_probe(struct i2c_client *i2c) |
9bb9e29c7 mfd: Add Ricoh RN... |
171 |
{ |
a99ab50db mfd: rn5t618: Add... |
172 |
const struct of_device_id *of_id; |
9bb9e29c7 mfd: Add Ricoh RN... |
173 174 |
struct rn5t618 *priv; int ret; |
a99ab50db mfd: rn5t618: Add... |
175 176 177 178 179 180 |
of_id = of_match_device(rn5t618_of_match, &i2c->dev); if (!of_id) { dev_err(&i2c->dev, "Failed to find matching DT ID "); return -EINVAL; } |
9bb9e29c7 mfd: Add Ricoh RN... |
181 182 183 184 185 |
priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; i2c_set_clientdata(i2c, priv); |
a99ab50db mfd: rn5t618: Add... |
186 |
priv->variant = (long)of_id->data; |
0c8160451 mfd: rn5t618: Add... |
187 188 |
priv->irq = i2c->irq; priv->dev = &i2c->dev; |
9bb9e29c7 mfd: Add Ricoh RN... |
189 190 191 192 193 194 195 196 |
priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config); if (IS_ERR(priv->regmap)) { ret = PTR_ERR(priv->regmap); dev_err(&i2c->dev, "regmap init failed: %d ", ret); return ret; } |
bc6167661 mfd: rn5t618: Add... |
197 198 199 200 201 202 203 204 205 206 |
if (priv->variant == RC5T619) ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE, rc5t619_cells, ARRAY_SIZE(rc5t619_cells), NULL, 0, NULL); else ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE, rn5t618_cells, ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL); |
9bb9e29c7 mfd: Add Ricoh RN... |
207 208 209 210 211 |
if (ret) { dev_err(&i2c->dev, "failed to add sub-devices: %d ", ret); return ret; } |
cf84dc0bb mfd: rn5t618: Mak... |
212 |
rn5t618_pm_power_off = i2c; |
fd65ae4cb mfd: rn5t618: Reg... |
213 |
if (of_device_is_system_power_controller(i2c->dev.of_node)) { |
a370f60a5 mfd: rn5t618: Reg... |
214 |
if (!pm_power_off) |
fd65ae4cb mfd: rn5t618: Reg... |
215 |
pm_power_off = rn5t618_power_off; |
a370f60a5 mfd: rn5t618: Reg... |
216 |
else |
fd65ae4cb mfd: rn5t618: Reg... |
217 218 |
dev_warn(&i2c->dev, "Poweroff callback already assigned "); |
a370f60a5 mfd: rn5t618: Reg... |
219 220 221 222 223 224 225 226 227 228 |
} rn5t618_restart_handler.notifier_call = rn5t618_restart; rn5t618_restart_handler.priority = 192; ret = register_restart_handler(&rn5t618_restart_handler); if (ret) { dev_err(&i2c->dev, "cannot register restart handler, %d ", ret); return ret; |
9bb9e29c7 mfd: Add Ricoh RN... |
229 |
} |
0c8160451 mfd: rn5t618: Add... |
230 |
return rn5t618_irq_init(priv); |
9bb9e29c7 mfd: Add Ricoh RN... |
231 232 233 234 |
} static int rn5t618_i2c_remove(struct i2c_client *i2c) { |
cf84dc0bb mfd: rn5t618: Mak... |
235 |
if (i2c == rn5t618_pm_power_off) { |
9bb9e29c7 mfd: Add Ricoh RN... |
236 237 238 |
rn5t618_pm_power_off = NULL; pm_power_off = NULL; } |
ecca790a1 mfd: rn5t618: Unr... |
239 |
unregister_restart_handler(&rn5t618_restart_handler); |
9bb9e29c7 mfd: Add Ricoh RN... |
240 241 |
return 0; } |
0c8160451 mfd: rn5t618: Add... |
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
static int __maybe_unused rn5t618_i2c_suspend(struct device *dev) { struct rn5t618 *priv = dev_get_drvdata(dev); if (priv->irq) disable_irq(priv->irq); return 0; } static int __maybe_unused rn5t618_i2c_resume(struct device *dev) { struct rn5t618 *priv = dev_get_drvdata(dev); if (priv->irq) enable_irq(priv->irq); return 0; } |
0c8160451 mfd: rn5t618: Add... |
261 262 263 |
static SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops, rn5t618_i2c_suspend, rn5t618_i2c_resume); |
9bb9e29c7 mfd: Add Ricoh RN... |
264 265 266 267 |
static struct i2c_driver rn5t618_i2c_driver = { .driver = { .name = "rn5t618", .of_match_table = of_match_ptr(rn5t618_of_match), |
0c8160451 mfd: rn5t618: Add... |
268 |
.pm = &rn5t618_i2c_dev_pm_ops, |
9bb9e29c7 mfd: Add Ricoh RN... |
269 |
}, |
7858658cd mfd: rn5t618: Cle... |
270 |
.probe_new = rn5t618_i2c_probe, |
9bb9e29c7 mfd: Add Ricoh RN... |
271 |
.remove = rn5t618_i2c_remove, |
9bb9e29c7 mfd: Add Ricoh RN... |
272 273 274 275 276 |
}; module_i2c_driver(rn5t618_i2c_driver); MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); |
a99ab50db mfd: rn5t618: Add... |
277 |
MODULE_DESCRIPTION("Ricoh RN5T567/618 MFD driver"); |
9bb9e29c7 mfd: Add Ricoh RN... |
278 |
MODULE_LICENSE("GPL v2"); |