brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 32f2553 Raw
247 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI LP8788 MFD - core interface4 *5 * Copyright 2012 Texas Instruments6 *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		0xA218 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)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	ret = mfd_add_devices(lp->dev, -1, lp8788_devs,199			      ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);200	if (ret)201		goto err_exit_irq;202 203	return 0;204 205err_exit_irq:206	lp8788_irq_exit(lp);207	return ret;208}209 210static void lp8788_remove(struct i2c_client *cl)211{212	struct lp8788 *lp = i2c_get_clientdata(cl);213 214	mfd_remove_devices(lp->dev);215	lp8788_irq_exit(lp);216}217 218static const struct i2c_device_id lp8788_ids[] = {219	{ "lp8788" },220	{ }221};222MODULE_DEVICE_TABLE(i2c, lp8788_ids);223 224static struct i2c_driver lp8788_driver = {225	.driver = {226		.name = "lp8788",227	},228	.probe = lp8788_probe,229	.remove = lp8788_remove,230	.id_table = lp8788_ids,231};232 233static int __init lp8788_init(void)234{235	return i2c_add_driver(&lp8788_driver);236}237subsys_initcall(lp8788_init);238 239static void __exit lp8788_exit(void)240{241	i2c_del_driver(&lp8788_driver);242}243module_exit(lp8788_exit);244 245MODULE_DESCRIPTION("TI LP8788 MFD Driver");246MODULE_AUTHOR("Milo Kim");247