tps65090.c 7.1 KB
Newer Older
V
Venu Byravarasu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Core driver for TI TPS65090 PMIC family
 *
 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.

 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.

 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65090.h>
28 29
#include <linux/of.h>
#include <linux/of_device.h>
V
Venu Byravarasu 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42
#include <linux/err.h>

#define NUM_INT_REG 2
#define TOTAL_NUM_REG 0x18

/* interrupt status registers */
#define TPS65090_INT_STS	0x0
#define TPS65090_INT_STS2	0x1

/* interrupt mask registers */
#define TPS65090_INT_MSK	0x2
#define TPS65090_INT_MSK2	0x3

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE		1
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE		2
#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE		3
#define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE	4
#define TPS65090_INT1_MASK_CHARGING_COMPLETE		5
#define TPS65090_INT1_MASK_OVERLOAD_DCDC1		6
#define TPS65090_INT1_MASK_OVERLOAD_DCDC2		7
#define TPS65090_INT2_MASK_OVERLOAD_DCDC3		0
#define TPS65090_INT2_MASK_OVERLOAD_FET1		1
#define TPS65090_INT2_MASK_OVERLOAD_FET2		2
#define TPS65090_INT2_MASK_OVERLOAD_FET3		3
#define TPS65090_INT2_MASK_OVERLOAD_FET4		4
#define TPS65090_INT2_MASK_OVERLOAD_FET5		5
#define TPS65090_INT2_MASK_OVERLOAD_FET6		6
#define TPS65090_INT2_MASK_OVERLOAD_FET7		7
V
Venu Byravarasu 已提交
58

59 60 61 62 63 64 65 66
static struct resource charger_resources[] = {
	{
		.start  = TPS65090_IRQ_VAC_STATUS_CHANGE,
		.end    = TPS65090_IRQ_VAC_STATUS_CHANGE,
		.flags  = IORESOURCE_IRQ,
	}
};

67
static const struct mfd_cell tps65090s[] = {
V
Venu Byravarasu 已提交
68
	{
69
		.name = "tps65090-pmic",
V
Venu Byravarasu 已提交
70 71
	},
	{
72
		.name = "tps65090-charger",
73 74
		.num_resources = ARRAY_SIZE(charger_resources),
		.resources = &charger_resources[0],
75
		.of_compatible = "ti,tps65090-charger",
V
Venu Byravarasu 已提交
76 77 78
	},
};

79 80 81 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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
static const struct regmap_irq tps65090_irqs[] = {
	/* INT1 IRQs*/
	[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
			.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
	},
	[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
			.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
	},
	[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
			.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
	},
	[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
			.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
	},
	[TPS65090_IRQ_CHARGING_COMPLETE] = {
			.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
	},
	[TPS65090_IRQ_OVERLOAD_DCDC1] = {
			.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
	},
	[TPS65090_IRQ_OVERLOAD_DCDC2] = {
			.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
	},
	/* INT2 IRQs*/
	[TPS65090_IRQ_OVERLOAD_DCDC3] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
	},
	[TPS65090_IRQ_OVERLOAD_FET1] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
	},
	[TPS65090_IRQ_OVERLOAD_FET2] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
	},
	[TPS65090_IRQ_OVERLOAD_FET3] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
	},
	[TPS65090_IRQ_OVERLOAD_FET4] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
	},
	[TPS65090_IRQ_OVERLOAD_FET5] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
	},
	[TPS65090_IRQ_OVERLOAD_FET6] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
	},
	[TPS65090_IRQ_OVERLOAD_FET7] = {
			.reg_offset = 1,
			.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
	},
};
V
Venu Byravarasu 已提交
136

137 138 139 140 141 142 143 144 145
static struct regmap_irq_chip tps65090_irq_chip = {
	.name = "tps65090",
	.irqs = tps65090_irqs,
	.num_irqs = ARRAY_SIZE(tps65090_irqs),
	.num_regs = NUM_INT_REG,
	.status_base = TPS65090_INT_STS,
	.mask_base = TPS65090_INT_MSK,
	.mask_invert = true,
};
V
Venu Byravarasu 已提交
146 147 148

static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
149
	if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
V
Venu Byravarasu 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163
		return true;
	else
		return false;
}

static const struct regmap_config tps65090_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = TOTAL_NUM_REG,
	.num_reg_defaults_raw = TOTAL_NUM_REG,
	.cache_type = REGCACHE_RBTREE,
	.volatile_reg = is_volatile_reg,
};

164 165 166 167 168 169 170 171
#ifdef CONFIG_OF
static const struct of_device_id tps65090_of_match[] = {
	{ .compatible = "ti,tps65090",},
	{},
};
MODULE_DEVICE_TABLE(of, tps65090_of_match);
#endif

B
Bill Pemberton 已提交
172
static int tps65090_i2c_probe(struct i2c_client *client,
V
Venu Byravarasu 已提交
173 174
					const struct i2c_device_id *id)
{
J
Jingoo Han 已提交
175
	struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
176
	int irq_base = 0;
V
Venu Byravarasu 已提交
177 178 179
	struct tps65090 *tps65090;
	int ret;

180 181 182
	if (!pdata && !client->dev.of_node) {
		dev_err(&client->dev,
			"tps65090 requires platform data or of_node\n");
V
Venu Byravarasu 已提交
183 184 185
		return -EINVAL;
	}

186 187 188
	if (pdata)
		irq_base = pdata->irq_base;

189 190 191
	tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
	if (!tps65090) {
		dev_err(&client->dev, "mem alloc for tps65090 failed\n");
V
Venu Byravarasu 已提交
192
		return -ENOMEM;
193
	}
V
Venu Byravarasu 已提交
194 195 196 197

	tps65090->dev = &client->dev;
	i2c_set_clientdata(client, tps65090);

198
	tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config);
V
Venu Byravarasu 已提交
199
	if (IS_ERR(tps65090->rmap)) {
200 201
		ret = PTR_ERR(tps65090->rmap);
		dev_err(&client->dev, "regmap_init failed with err: %d\n", ret);
202 203 204 205 206
		return ret;
	}

	if (client->irq) {
		ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
207
			IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
208 209 210 211 212 213
			&tps65090_irq_chip, &tps65090->irq_data);
			if (ret) {
				dev_err(&client->dev,
					"IRQ init failed with err: %d\n", ret);
			return ret;
		}
214
	}
V
Venu Byravarasu 已提交
215 216

	ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
217
		ARRAY_SIZE(tps65090s), NULL,
218
		0, regmap_irq_get_domain(tps65090->irq_data));
V
Venu Byravarasu 已提交
219 220 221
	if (ret) {
		dev_err(&client->dev, "add mfd devices failed with err: %d\n",
			ret);
222
		goto err_irq_exit;
V
Venu Byravarasu 已提交
223 224 225 226 227 228
	}

	return 0;

err_irq_exit:
	if (client->irq)
229
		regmap_del_irq_chip(client->irq, tps65090->irq_data);
V
Venu Byravarasu 已提交
230 231 232
	return ret;
}

B
Bill Pemberton 已提交
233
static int tps65090_i2c_remove(struct i2c_client *client)
V
Venu Byravarasu 已提交
234 235 236 237 238
{
	struct tps65090 *tps65090 = i2c_get_clientdata(client);

	mfd_remove_devices(tps65090->dev);
	if (client->irq)
239
		regmap_del_irq_chip(client->irq, tps65090->irq_data);
V
Venu Byravarasu 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253

	return 0;
}

static const struct i2c_device_id tps65090_id_table[] = {
	{ "tps65090", 0 },
	{ },
};
MODULE_DEVICE_TABLE(i2c, tps65090_id_table);

static struct i2c_driver tps65090_driver = {
	.driver	= {
		.name	= "tps65090",
		.owner	= THIS_MODULE,
254
		.of_match_table = of_match_ptr(tps65090_of_match),
V
Venu Byravarasu 已提交
255 256
	},
	.probe		= tps65090_i2c_probe,
B
Bill Pemberton 已提交
257
	.remove		= tps65090_i2c_remove,
V
Venu Byravarasu 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	.id_table	= tps65090_id_table,
};

static int __init tps65090_init(void)
{
	return i2c_add_driver(&tps65090_driver);
}
subsys_initcall(tps65090_init);

static void __exit tps65090_exit(void)
{
	i2c_del_driver(&tps65090_driver);
}
module_exit(tps65090_exit);

MODULE_DESCRIPTION("TPS65090 core driver");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
MODULE_LICENSE("GPL v2");