18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MFD core driver for the Richtek RT5033.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * RT5033 comprises multiple sub-devices switcing charger, fuel gauge,
68c2ecf20Sopenharmony_ci * flash LED, current source, LDO and BUCK regulators.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
98c2ecf20Sopenharmony_ci * Author: Beomho Seo <beomho.seo@samsung.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/of_device.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/core.h>
178c2ecf20Sopenharmony_ci#include <linux/mfd/rt5033.h>
188c2ecf20Sopenharmony_ci#include <linux/mfd/rt5033-private.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const struct regmap_irq rt5033_irqs[] = {
218c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_BUCKOCP, },
228c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_BUCKLV, },
238c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_SAFELDOLV, },
248c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_LDOLV, },
258c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_OT, },
268c2ecf20Sopenharmony_ci	{ .mask = RT5033_PMIC_IRQ_VDDA_UV, },
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const struct regmap_irq_chip rt5033_irq_chip = {
308c2ecf20Sopenharmony_ci	.name		= "rt5033",
318c2ecf20Sopenharmony_ci	.status_base	= RT5033_REG_PMIC_IRQ_STAT,
328c2ecf20Sopenharmony_ci	.mask_base	= RT5033_REG_PMIC_IRQ_CTRL,
338c2ecf20Sopenharmony_ci	.mask_invert	= true,
348c2ecf20Sopenharmony_ci	.num_regs	= 1,
358c2ecf20Sopenharmony_ci	.irqs		= rt5033_irqs,
368c2ecf20Sopenharmony_ci	.num_irqs	= ARRAY_SIZE(rt5033_irqs),
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic const struct mfd_cell rt5033_devs[] = {
408c2ecf20Sopenharmony_ci	{ .name = "rt5033-regulator", },
418c2ecf20Sopenharmony_ci	{
428c2ecf20Sopenharmony_ci		.name = "rt5033-charger",
438c2ecf20Sopenharmony_ci		.of_compatible = "richtek,rt5033-charger",
448c2ecf20Sopenharmony_ci	}, {
458c2ecf20Sopenharmony_ci		.name = "rt5033-led",
468c2ecf20Sopenharmony_ci		.of_compatible = "richtek,rt5033-led",
478c2ecf20Sopenharmony_ci	},
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic const struct regmap_config rt5033_regmap_config = {
518c2ecf20Sopenharmony_ci	.reg_bits	= 8,
528c2ecf20Sopenharmony_ci	.val_bits	= 8,
538c2ecf20Sopenharmony_ci	.max_register	= RT5033_REG_END,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int rt5033_i2c_probe(struct i2c_client *i2c,
578c2ecf20Sopenharmony_ci				const struct i2c_device_id *id)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct rt5033_dev *rt5033;
608c2ecf20Sopenharmony_ci	unsigned int dev_id;
618c2ecf20Sopenharmony_ci	int ret;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	rt5033 = devm_kzalloc(&i2c->dev, sizeof(*rt5033), GFP_KERNEL);
648c2ecf20Sopenharmony_ci	if (!rt5033)
658c2ecf20Sopenharmony_ci		return -ENOMEM;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	i2c_set_clientdata(i2c, rt5033);
688c2ecf20Sopenharmony_ci	rt5033->dev = &i2c->dev;
698c2ecf20Sopenharmony_ci	rt5033->irq = i2c->irq;
708c2ecf20Sopenharmony_ci	rt5033->wakeup = true;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	rt5033->regmap = devm_regmap_init_i2c(i2c, &rt5033_regmap_config);
738c2ecf20Sopenharmony_ci	if (IS_ERR(rt5033->regmap)) {
748c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "Failed to allocate register map.\n");
758c2ecf20Sopenharmony_ci		return PTR_ERR(rt5033->regmap);
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	ret = regmap_read(rt5033->regmap, RT5033_REG_DEVICE_ID, &dev_id);
798c2ecf20Sopenharmony_ci	if (ret) {
808c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "Device not found\n");
818c2ecf20Sopenharmony_ci		return -ENODEV;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	dev_info(&i2c->dev, "Device found Device ID: %04x\n", dev_id);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq,
868c2ecf20Sopenharmony_ci			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
878c2ecf20Sopenharmony_ci			0, &rt5033_irq_chip, &rt5033->irq_data);
888c2ecf20Sopenharmony_ci	if (ret) {
898c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
908c2ecf20Sopenharmony_ci							rt5033->irq, ret);
918c2ecf20Sopenharmony_ci		return ret;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	ret = devm_mfd_add_devices(rt5033->dev, -1, rt5033_devs,
958c2ecf20Sopenharmony_ci				   ARRAY_SIZE(rt5033_devs), NULL, 0,
968c2ecf20Sopenharmony_ci				   regmap_irq_get_domain(rt5033->irq_data));
978c2ecf20Sopenharmony_ci	if (ret < 0) {
988c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "Failed to add RT5033 child devices.\n");
998c2ecf20Sopenharmony_ci		return ret;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	device_init_wakeup(rt5033->dev, rt5033->wakeup);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic const struct i2c_device_id rt5033_i2c_id[] = {
1088c2ecf20Sopenharmony_ci	{ "rt5033", },
1098c2ecf20Sopenharmony_ci	{ }
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, rt5033_i2c_id);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic const struct of_device_id rt5033_dt_match[] = {
1148c2ecf20Sopenharmony_ci	{ .compatible = "richtek,rt5033", },
1158c2ecf20Sopenharmony_ci	{ }
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rt5033_dt_match);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic struct i2c_driver rt5033_driver = {
1208c2ecf20Sopenharmony_ci	.driver = {
1218c2ecf20Sopenharmony_ci		.name = "rt5033",
1228c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(rt5033_dt_match),
1238c2ecf20Sopenharmony_ci	},
1248c2ecf20Sopenharmony_ci	.probe = rt5033_i2c_probe,
1258c2ecf20Sopenharmony_ci	.id_table = rt5033_i2c_id,
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_cimodule_i2c_driver(rt5033_driver);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Richtek RT5033 multi-function core driver");
1308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
1318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
132