cregit-Linux how code gets into the kernel

Release 4.14 drivers/mfd/sec-core.c

Directory: drivers/mfd
/*
 * sec-core.c
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd
 *              http://www.samsung.com
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mps15.h>
#include <linux/mfd/samsung/s2mpu02.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regmap.h>


static const struct mfd_cell s5m8751_devs[] = {
	{
		.name = "s5m8751-pmic",
        }, {
		.name = "s5m-charger",
        }, {
		.name = "s5m8751-codec",
        },
};


static const struct mfd_cell s5m8763_devs[] = {
	{
		.name = "s5m8763-pmic",
        }, {
		.name = "s5m-rtc",
        }, {
		.name = "s5m-charger",
        },
};


static const struct mfd_cell s5m8767_devs[] = {
	{
		.name = "s5m8767-pmic",
        }, {
		.name = "s5m-rtc",
        }, {
		.name = "s5m8767-clk",
		.of_compatible = "samsung,s5m8767-clk",
        }
};


static const struct mfd_cell s2mps11_devs[] = {
	{
		.name = "s2mps11-regulator",
        }, {
		.name = "s2mps14-rtc",
        }, {
		.name = "s2mps11-clk",
		.of_compatible = "samsung,s2mps11-clk",
        }
};


static const struct mfd_cell s2mps13_devs[] = {
	{ .name = "s2mps13-regulator", },
	{ .name = "s2mps13-rtc", },
	{
		.name = "s2mps13-clk",
		.of_compatible = "samsung,s2mps13-clk",
        },
};


static const struct mfd_cell s2mps14_devs[] = {
	{
		.name = "s2mps14-regulator",
        }, {
		.name = "s2mps14-rtc",
        }, {
		.name = "s2mps14-clk",
		.of_compatible = "samsung,s2mps14-clk",
        }
};


static const struct mfd_cell s2mps15_devs[] = {
	{
		.name = "s2mps15-regulator",
        }, {
		.name = "s2mps15-rtc",
        }, {
		.name = "s2mps13-clk",
		.of_compatible = "samsung,s2mps13-clk",
        },
};


static const struct mfd_cell s2mpa01_devs[] = {
	{
		.name = "s2mpa01-pmic",
        },
};


static const struct mfd_cell s2mpu02_devs[] = {
	{
		.name = "s2mpu02-regulator",
        },
};

#ifdef CONFIG_OF

static const struct of_device_id sec_dt_match[] = {
	{	.compatible = "samsung,s5m8767-pmic",
		.data = (void *)S5M8767X,
        }, {
		.compatible = "samsung,s2mps11-pmic",
		.data = (void *)S2MPS11X,
        }, {
		.compatible = "samsung,s2mps13-pmic",
		.data = (void *)S2MPS13X,
        }, {
		.compatible = "samsung,s2mps14-pmic",
		.data = (void *)S2MPS14X,
        }, {
		.compatible = "samsung,s2mps15-pmic",
		.data = (void *)S2MPS15X,
        }, {
		.compatible = "samsung,s2mpa01-pmic",
		.data = (void *)S2MPA01,
        }, {
		.compatible = "samsung,s2mpu02-pmic",
		.data = (void *)S2MPU02,
        }, {
		/* Sentinel */
	},
};
#endif


static bool s2mpa01_volatile(struct device *dev, unsigned int reg) { switch (reg) { case S2MPA01_REG_INT1M: case S2MPA01_REG_INT2M: case S2MPA01_REG_INT3M: return false; default: return true; } }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Kamat37100.00%1100.00%
Total37100.00%1100.00%


static bool s2mps11_volatile(struct device *dev, unsigned int reg) { switch (reg) { case S2MPS11_REG_INT1M: case S2MPS11_REG_INT2M: case S2MPS11_REG_INT3M: return false; default: return true; } }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown37100.00%1100.00%
Total37100.00%1100.00%


static bool s2mpu02_volatile(struct device *dev, unsigned int reg) { switch (reg) { case S2MPU02_REG_INT1M: case S2MPU02_REG_INT2M: case S2MPU02_REG_INT3M: return false; default: return true; } }

Contributors

PersonTokensPropCommitsCommitProp
Chanwoo Choi37100.00%1100.00%
Total37100.00%1100.00%


static bool s5m8763_volatile(struct device *dev, unsigned int reg) { switch (reg) { case S5M8763_REG_IRQM1: case S5M8763_REG_IRQM2: case S5M8763_REG_IRQM3: case S5M8763_REG_IRQM4: return false; default: return true; } }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown40100.00%1100.00%
Total40100.00%1100.00%

static const struct regmap_config sec_regmap_config = { .reg_bits = 8, .val_bits = 8, }; static const struct regmap_config s2mpa01_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPA01_REG_LDO_OVCB4, .volatile_reg = s2mpa01_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s2mps11_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS11_REG_L38CTRL, .volatile_reg = s2mps11_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s2mps13_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS13_REG_LDODSCH5, .volatile_reg = s2mps11_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s2mps14_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS14_REG_LDODSCH3, .volatile_reg = s2mps11_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s2mps15_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS15_REG_LDODSCH4, .volatile_reg = s2mps11_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s2mpu02_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPU02_REG_DVSDATA, .volatile_reg = s2mpu02_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s5m8763_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S5M8763_REG_LBCNFG2, .volatile_reg = s5m8763_volatile, .cache_type = REGCACHE_FLAT, }; static const struct regmap_config s5m8767_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S5M8767_REG_LDO28CTRL, .volatile_reg = s2mps11_volatile, .cache_type = REGCACHE_FLAT, };
static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) { unsigned int val; /* For each device type, the REG_ID is always the first register */ if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski42100.00%1100.00%
Total42100.00%1100.00%


static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) { int err; if (sec_pmic->device_type != S2MPS13X) return; if (sec_pmic->pdata->disable_wrstbi) { /* * If WRSTBI pin is pulled down this feature must be disabled * because each Suspend to RAM will trigger buck voltage reset * to default values. */ err = regmap_update_bits(sec_pmic->regmap_pmic, S2MPS13_REG_WRSTBI, S2MPS13_REG_WRSTBI_MASK, 0x0); if (err) dev_warn(sec_pmic->dev, "Cannot initialize WRSTBI config: %d\n", err); } }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski64100.00%1100.00%
Total64100.00%1100.00%

#ifdef CONFIG_OF /* * Only the common platform data elements for s5m8767 are parsed here from the * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and * others have to parse their own platform data elements from device tree. * * The s5m8767 platform data structure is instantiated here and the drivers for * the sub-modules need not instantiate another instance while parsing their * platform data. */
static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( struct device *dev) { struct sec_platform_data *pd; pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); /* * ToDo: the 'wakeup' member in the platform data is more of a linux * specfic information. Hence, there is no binding for that yet and * not parsed here. */ pd->manual_poweroff = of_property_read_bool(dev->of_node, "samsung,s2mps11-acokb-ground"); pd->disable_wrstbi = of_property_read_bool(dev->of_node, "samsung,s2mps11-wrstbi-ground"); return pd; }

Contributors

PersonTokensPropCommitsCommitProp
Amit Daniel Kachhap4965.33%133.33%
Krzysztof Kozlowski2634.67%266.67%
Total75100.00%3100.00%

#else
static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( struct device *dev) { return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Amit Daniel Kachhap1487.50%133.33%
Mark Brown16.25%133.33%
Wei Yongjun16.25%133.33%
Total16100.00%3100.00%

#endif
static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, const struct i2c_device_id *id) { #ifdef CONFIG_OF if (i2c->dev.of_node) { const struct of_device_id *match; match = of_match_node(sec_dt_match, i2c->dev.of_node); return (unsigned long)match->data; } #endif return id->driver_data; }

Contributors

PersonTokensPropCommitsCommitProp
Amit Daniel Kachhap6394.03%150.00%
Pankaj Dubey45.97%150.00%
Total67100.00%2100.00%


static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); const struct regmap_config *regmap; const struct mfd_cell *sec_devs; struct sec_pmic_dev *sec_pmic; unsigned long device_type; int ret, num_sec_devs; sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), GFP_KERNEL); if (sec_pmic == NULL) return -ENOMEM; i2c_set_clientdata(i2c, sec_pmic); sec_pmic->dev = &i2c->dev; sec_pmic->i2c = i2c; sec_pmic->irq = i2c->irq; device_type = sec_i2c_get_driver_data(i2c, id); if (sec_pmic->dev->of_node) { pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); if (IS_ERR(pdata)) { ret = PTR_ERR(pdata); return ret; } pdata->device_type = device_type; } if (pdata) { sec_pmic->device_type = pdata->device_type; sec_pmic->irq_base = pdata->irq_base; sec_pmic->wakeup = pdata->wakeup; sec_pmic->pdata = pdata; } switch (sec_pmic->device_type) { case S2MPA01: regmap = &s2mpa01_regmap_config; break; case S2MPS11X: regmap = &s2mps11_regmap_config; break; case S2MPS13X: regmap = &s2mps13_regmap_config; break; case S2MPS14X: regmap = &s2mps14_regmap_config; break; case S2MPS15X: regmap = &s2mps15_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; break; case S2MPU02: regmap = &s2mpu02_regmap_config; break; default: regmap = &sec_regmap_config; break; } sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); if (IS_ERR(sec_pmic->regmap_pmic)) { ret = PTR_ERR(sec_pmic->regmap_pmic); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); return ret; } if (pdata && pdata->cfg_pmic_irq) pdata->cfg_pmic_irq(); sec_irq_init(sec_pmic); pm_runtime_set_active(sec_pmic->dev); switch (sec_pmic->device_type) { case S5M8751X: sec_devs = s5m8751_devs; num_sec_devs = ARRAY_SIZE(s5m8751_devs); break; case S5M8763X: sec_devs = s5m8763_devs; num_sec_devs = ARRAY_SIZE(s5m8763_devs); break; case S5M8767X: sec_devs = s5m8767_devs; num_sec_devs = ARRAY_SIZE(s5m8767_devs); break; case S2MPA01: sec_devs = s2mpa01_devs; num_sec_devs = ARRAY_SIZE(s2mpa01_devs); break; case S2MPS11X: sec_devs = s2mps11_devs; num_sec_devs = ARRAY_SIZE(s2mps11_devs); break; case S2MPS13X: sec_devs = s2mps13_devs; num_sec_devs = ARRAY_SIZE(s2mps13_devs); break; case S2MPS14X: sec_devs = s2mps14_devs; num_sec_devs = ARRAY_SIZE(s2mps14_devs); break; case S2MPS15X: sec_devs = s2mps15_devs; num_sec_devs = ARRAY_SIZE(s2mps15_devs); break; case S2MPU02: sec_devs = s2mpu02_devs; num_sec_devs = ARRAY_SIZE(s2mpu02_devs); break; default: /* If this happens the probe function is problem */ BUG(); } ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL, 0, NULL); if (ret) return ret; device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); sec_pmic_configure(sec_pmic); sec_pmic_dump_rev(sec_pmic); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Sangbeom Kim24343.24%520.83%
Chanwoo Choi9617.08%416.67%
Krzysztof Kozlowski6110.85%625.00%
Amit Daniel Kachhap539.43%14.17%
Mark Brown498.72%14.17%
Thomas Abraham244.27%14.17%
Sachin Kamat203.56%14.17%
Axel Lin61.07%28.33%
Jingoo Han40.71%14.17%
Laxman Dewangan40.71%14.17%
Jonghwan Choi20.36%14.17%
Total562100.00%24100.00%


static void sec_pmic_shutdown(struct i2c_client *i2c) { struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); unsigned int reg, mask; if (!sec_pmic->pdata->manual_poweroff) return; switch (sec_pmic->device_type) { case S2MPS11X: reg = S2MPS11_REG_CTRL1; mask = S2MPS11_CTRL1_PWRHOLD_MASK; break; default: /* * Currently only one board with S2MPS11 needs this, so just * ignore the rest. */ dev_warn(sec_pmic->dev, "Unsupported device %lu for manual power off\n", sec_pmic->device_type); return; } regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski86100.00%1100.00%
Total86100.00%1100.00%

#ifdef CONFIG_PM_SLEEP
static int sec_pmic_suspend(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); if (device_may_wakeup(dev)) enable_irq_wake(sec_pmic->irq); /* * PMIC IRQ must be disabled during suspend for RTC alarm * to work properly. * When device is woken up from suspend, an * interrupt occurs before resuming I2C bus controller. * The interrupt is handled by regmap_irq_thread which tries * to read RTC registers. This read fails (I2C is still * suspended) and RTC Alarm interrupt is disabled. */ disable_irq(sec_pmic->irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski5598.21%266.67%
Geliang Tang11.79%133.33%
Total56100.00%3100.00%


static int sec_pmic_resume(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); if (device_may_wakeup(dev)) disable_irq_wake(sec_pmic->irq); enable_irq(sec_pmic->irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski5498.18%150.00%
Geliang Tang11.82%150.00%
Total55100.00%2100.00%

#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); static const struct i2c_device_id sec_pmic_id[] = { { "sec_pmic", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, sec_pmic_id); static struct i2c_driver sec_pmic_driver = { .driver = { .name = "sec_pmic", .pm = &sec_pmic_pm_ops, .of_match_table = of_match_ptr(sec_dt_match), }, .probe = sec_pmic_probe, .shutdown = sec_pmic_shutdown, .id_table = sec_pmic_id, };
static int __init sec_pmic_init(void) { return i2c_add_driver(&sec_pmic_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Sangbeom Kim16100.00%2100.00%
Total16100.00%2100.00%

subsys_initcall(sec_pmic_init);
static void __exit sec_pmic_exit(void) { i2c_del_driver(&sec_pmic_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Sangbeom Kim15100.00%2100.00%
Total15100.00%2100.00%

module_exit(sec_pmic_exit); MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); MODULE_DESCRIPTION("Core support for the S5M MFD"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Krzysztof Kozlowski51824.99%1329.55%
Sangbeom Kim50124.17%613.64%
Chanwoo Choi28513.75%49.09%
Mark Brown23211.19%36.82%
Amit Daniel Kachhap22610.90%12.27%
Sachin Kamat1316.32%24.55%
Thomas Abraham1115.35%12.27%
Yadwinder Singh Brar241.16%24.55%
Geert Uytterhoeven100.48%24.55%
Tushar Behera80.39%12.27%
Axel Lin60.29%24.55%
Jingoo Han40.19%12.27%
Alim Akhtar40.19%12.27%
Pankaj Dubey40.19%12.27%
Laxman Dewangan40.19%12.27%
Jonghwan Choi20.10%12.27%
Geliang Tang20.10%12.27%
Wei Yongjun10.05%12.27%
Total2073100.00%44100.00%
Directory: drivers/mfd
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.