cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lp8788.c (5231B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TI LP8788 MFD - core interface
      4 *
      5 * Copyright 2012 Texas Instruments
      6 *
      7 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
      8 */
      9
     10#include <linux/err.h>
     11#include <linux/i2c.h>
     12#include <linux/mfd/core.h>
     13#include <linux/mfd/lp8788.h>
     14#include <linux/module.h>
     15#include <linux/slab.h>
     16
     17#define MAX_LP8788_REGISTERS		0xA2
     18
     19#define MFD_DEV_SIMPLE(_name)					\
     20{								\
     21	.name = LP8788_DEV_##_name,				\
     22}
     23
     24#define MFD_DEV_WITH_ID(_name, _id)				\
     25{								\
     26	.name = LP8788_DEV_##_name,				\
     27	.id = _id,						\
     28}
     29
     30#define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource)	\
     31{								\
     32	.name = LP8788_DEV_##_name,				\
     33	.resources = _resource,					\
     34	.num_resources = num_resource,				\
     35}
     36
     37static const struct resource chg_irqs[] = {
     38	/* Charger Interrupts */
     39	{
     40		.start = LP8788_INT_CHG_INPUT_STATE,
     41		.end   = LP8788_INT_PRECHG_TIMEOUT,
     42		.name  = LP8788_CHG_IRQ,
     43		.flags = IORESOURCE_IRQ,
     44	},
     45	/* Power Routing Switch Interrupts */
     46	{
     47		.start = LP8788_INT_ENTER_SYS_SUPPORT,
     48		.end   = LP8788_INT_EXIT_SYS_SUPPORT,
     49		.name  = LP8788_PRSW_IRQ,
     50		.flags = IORESOURCE_IRQ,
     51	},
     52	/* Battery Interrupts */
     53	{
     54		.start = LP8788_INT_BATT_LOW,
     55		.end   = LP8788_INT_NO_BATT,
     56		.name  = LP8788_BATT_IRQ,
     57		.flags = IORESOURCE_IRQ,
     58	},
     59};
     60
     61static const struct resource rtc_irqs[] = {
     62	{
     63		.start = LP8788_INT_RTC_ALARM1,
     64		.end   = LP8788_INT_RTC_ALARM2,
     65		.name  = LP8788_ALM_IRQ,
     66		.flags = IORESOURCE_IRQ,
     67	},
     68};
     69
     70static const struct mfd_cell lp8788_devs[] = {
     71	/* 4 bucks */
     72	MFD_DEV_WITH_ID(BUCK, 1),
     73	MFD_DEV_WITH_ID(BUCK, 2),
     74	MFD_DEV_WITH_ID(BUCK, 3),
     75	MFD_DEV_WITH_ID(BUCK, 4),
     76
     77	/* 12 digital ldos */
     78	MFD_DEV_WITH_ID(DLDO, 1),
     79	MFD_DEV_WITH_ID(DLDO, 2),
     80	MFD_DEV_WITH_ID(DLDO, 3),
     81	MFD_DEV_WITH_ID(DLDO, 4),
     82	MFD_DEV_WITH_ID(DLDO, 5),
     83	MFD_DEV_WITH_ID(DLDO, 6),
     84	MFD_DEV_WITH_ID(DLDO, 7),
     85	MFD_DEV_WITH_ID(DLDO, 8),
     86	MFD_DEV_WITH_ID(DLDO, 9),
     87	MFD_DEV_WITH_ID(DLDO, 10),
     88	MFD_DEV_WITH_ID(DLDO, 11),
     89	MFD_DEV_WITH_ID(DLDO, 12),
     90
     91	/* 10 analog ldos */
     92	MFD_DEV_WITH_ID(ALDO, 1),
     93	MFD_DEV_WITH_ID(ALDO, 2),
     94	MFD_DEV_WITH_ID(ALDO, 3),
     95	MFD_DEV_WITH_ID(ALDO, 4),
     96	MFD_DEV_WITH_ID(ALDO, 5),
     97	MFD_DEV_WITH_ID(ALDO, 6),
     98	MFD_DEV_WITH_ID(ALDO, 7),
     99	MFD_DEV_WITH_ID(ALDO, 8),
    100	MFD_DEV_WITH_ID(ALDO, 9),
    101	MFD_DEV_WITH_ID(ALDO, 10),
    102
    103	/* ADC */
    104	MFD_DEV_SIMPLE(ADC),
    105
    106	/* battery charger */
    107	MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)),
    108
    109	/* rtc */
    110	MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)),
    111
    112	/* backlight */
    113	MFD_DEV_SIMPLE(BACKLIGHT),
    114
    115	/* current sink for vibrator */
    116	MFD_DEV_SIMPLE(VIBRATOR),
    117
    118	/* current sink for keypad LED */
    119	MFD_DEV_SIMPLE(KEYLED),
    120};
    121
    122int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data)
    123{
    124	int ret;
    125	unsigned int val;
    126
    127	ret = regmap_read(lp->regmap, reg, &val);
    128	if (ret < 0) {
    129		dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
    130		return ret;
    131	}
    132
    133	*data = (u8)val;
    134	return 0;
    135}
    136EXPORT_SYMBOL_GPL(lp8788_read_byte);
    137
    138int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count)
    139{
    140	return regmap_bulk_read(lp->regmap, reg, data, count);
    141}
    142EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes);
    143
    144int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data)
    145{
    146	return regmap_write(lp->regmap, reg, data);
    147}
    148EXPORT_SYMBOL_GPL(lp8788_write_byte);
    149
    150int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data)
    151{
    152	return regmap_update_bits(lp->regmap, reg, mask, data);
    153}
    154EXPORT_SYMBOL_GPL(lp8788_update_bits);
    155
    156static int lp8788_platform_init(struct lp8788 *lp)
    157{
    158	struct lp8788_platform_data *pdata = lp->pdata;
    159
    160	return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0;
    161}
    162
    163static const struct regmap_config lp8788_regmap_config = {
    164	.reg_bits = 8,
    165	.val_bits = 8,
    166	.max_register = MAX_LP8788_REGISTERS,
    167};
    168
    169static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
    170{
    171	struct lp8788 *lp;
    172	struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev);
    173	int ret;
    174
    175	lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL);
    176	if (!lp)
    177		return -ENOMEM;
    178
    179	lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config);
    180	if (IS_ERR(lp->regmap)) {
    181		ret = PTR_ERR(lp->regmap);
    182		dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
    183		return ret;
    184	}
    185
    186	lp->pdata = pdata;
    187	lp->dev = &cl->dev;
    188	i2c_set_clientdata(cl, lp);
    189
    190	ret = lp8788_platform_init(lp);
    191	if (ret)
    192		return ret;
    193
    194	ret = lp8788_irq_init(lp, cl->irq);
    195	if (ret)
    196		return ret;
    197
    198	return mfd_add_devices(lp->dev, -1, lp8788_devs,
    199			       ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
    200}
    201
    202static int lp8788_remove(struct i2c_client *cl)
    203{
    204	struct lp8788 *lp = i2c_get_clientdata(cl);
    205
    206	mfd_remove_devices(lp->dev);
    207	lp8788_irq_exit(lp);
    208	return 0;
    209}
    210
    211static const struct i2c_device_id lp8788_ids[] = {
    212	{"lp8788", 0},
    213	{ }
    214};
    215MODULE_DEVICE_TABLE(i2c, lp8788_ids);
    216
    217static struct i2c_driver lp8788_driver = {
    218	.driver = {
    219		.name = "lp8788",
    220	},
    221	.probe = lp8788_probe,
    222	.remove = lp8788_remove,
    223	.id_table = lp8788_ids,
    224};
    225
    226static int __init lp8788_init(void)
    227{
    228	return i2c_add_driver(&lp8788_driver);
    229}
    230subsys_initcall(lp8788_init);
    231
    232static void __exit lp8788_exit(void)
    233{
    234	i2c_del_driver(&lp8788_driver);
    235}
    236module_exit(lp8788_exit);
    237
    238MODULE_DESCRIPTION("TI LP8788 MFD Driver");
    239MODULE_AUTHOR("Milo Kim");
    240MODULE_LICENSE("GPL");