sec-core.c 10.8 KB
Newer Older
S
Sangbeom Kim 已提交
1
/*
2
 * sec-core.c
S
Sangbeom Kim 已提交
3
 *
4
 * Copyright (c) 2012 Samsung Electronics Co., Ltd
S
Sangbeom Kim 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *              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>
20
#include <linux/of.h>
21
#include <linux/of_irq.h>
S
Sangbeom Kim 已提交
22 23 24 25
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
S
Sangbeom Kim 已提交
26 27
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
28
#include <linux/mfd/samsung/s2mpa01.h>
29
#include <linux/mfd/samsung/s2mps11.h>
30
#include <linux/mfd/samsung/s2mps14.h>
31
#include <linux/mfd/samsung/s2mpu02.h>
32 33
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
34
#include <linux/regulator/machine.h>
S
Sangbeom Kim 已提交
35 36
#include <linux/regmap.h>

37
static const struct mfd_cell s5m8751_devs[] = {
38 39 40 41 42 43 44 45 46
	{
		.name = "s5m8751-pmic",
	}, {
		.name = "s5m-charger",
	}, {
		.name = "s5m8751-codec",
	},
};

47
static const struct mfd_cell s5m8763_devs[] = {
48 49 50 51 52 53 54 55 56
	{
		.name = "s5m8763-pmic",
	}, {
		.name = "s5m-rtc",
	}, {
		.name = "s5m-charger",
	},
};

57
static const struct mfd_cell s5m8767_devs[] = {
S
Sangbeom Kim 已提交
58 59 60 61
	{
		.name = "s5m8767-pmic",
	}, {
		.name = "s5m-rtc",
62 63
	}, {
		.name = "s5m8767-clk",
64
		.of_compatible = "samsung,s5m8767-clk",
65
	}
S
Sangbeom Kim 已提交
66 67
};

68
static const struct mfd_cell s2mps11_devs[] = {
69 70
	{
		.name = "s2mps11-pmic",
71 72
	}, {
		.name = "s2mps11-clk",
73
		.of_compatible = "samsung,s2mps11-clk",
74
	}
75 76
};

77 78 79 80 81 82 83
static const struct mfd_cell s2mps14_devs[] = {
	{
		.name = "s2mps14-pmic",
	}, {
		.name = "s2mps14-rtc",
	}, {
		.name = "s2mps14-clk",
84
		.of_compatible = "samsung,s2mps14-clk",
85 86 87
	}
};

88 89 90 91 92 93
static const struct mfd_cell s2mpa01_devs[] = {
	{
		.name = "s2mpa01-pmic",
	},
};

94 95 96 97 98 99 100 101 102
static const struct mfd_cell s2mpu02_devs[] = {
	{ .name = "s2mpu02-pmic", },
	{ .name = "s2mpu02-rtc", },
	{
		.name = "s2mpu02-clk",
		.of_compatible = "samsung,s2mpu02-clk",
	}
};

103
#ifdef CONFIG_OF
104
static const struct of_device_id sec_dt_match[] = {
105 106
	{	.compatible = "samsung,s5m8767-pmic",
		.data = (void *)S5M8767X,
107 108
	}, {
		.compatible = "samsung,s2mps11-pmic",
109
		.data = (void *)S2MPS11X,
110 111
	}, {
		.compatible = "samsung,s2mps14-pmic",
112
		.data = (void *)S2MPS14X,
113 114 115
	}, {
		.compatible = "samsung,s2mpa01-pmic",
		.data = (void *)S2MPA01,
116 117 118
	}, {
		.compatible = "samsung,s2mpu02-pmic",
		.data = (void *)S2MPU02,
119 120
	}, {
		/* Sentinel */
121
	},
122 123 124
};
#endif

125 126 127 128 129 130 131 132 133 134 135 136
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;
	}
}

137 138 139 140 141 142 143 144 145 146 147 148
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;
	}
}

149 150 151 152 153 154 155 156 157 158 159 160
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;
	}
}

161 162 163 164 165 166 167 168 169 170 171 172 173
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;
	}
}

174
static const struct regmap_config sec_regmap_config = {
S
Sangbeom Kim 已提交
175 176 177 178
	.reg_bits = 8,
	.val_bits = 8,
};

179 180 181 182 183 184 185 186 187
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,
};

188
static const struct regmap_config s2mps11_regmap_config = {
189 190 191 192
	.reg_bits = 8,
	.val_bits = 8,

	.max_register = S2MPS11_REG_L38CTRL,
193 194
	.volatile_reg = s2mps11_volatile,
	.cache_type = REGCACHE_FLAT,
195 196
};

197 198 199 200 201 202 203 204 205
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,
};

206 207 208 209 210 211 212 213 214
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,
};

215
static const struct regmap_config s5m8763_regmap_config = {
216 217 218 219
	.reg_bits = 8,
	.val_bits = 8,

	.max_register = S5M8763_REG_LBCNFG2,
220 221
	.volatile_reg = s5m8763_volatile,
	.cache_type = REGCACHE_FLAT,
222 223
};

224
static const struct regmap_config s5m8767_regmap_config = {
225 226 227 228
	.reg_bits = 8,
	.val_bits = 8,

	.max_register = S5M8767_REG_LDO28CTRL,
229 230
	.volatile_reg = s2mps11_volatile,
	.cache_type = REGCACHE_FLAT,
231
};
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

#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) {
		dev_err(dev, "could not allocate memory for pdata\n");
		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.
	 */

	return pd;
}
#else
263
static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
264 265
					struct device *dev)
{
266
	return NULL;
267 268 269
}
#endif

270
static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
271 272 273 274 275
						const struct i2c_device_id *id)
{
#ifdef CONFIG_OF
	if (i2c->dev.of_node) {
		const struct of_device_id *match;
276

277
		match = of_match_node(sec_dt_match, i2c->dev.of_node);
278
		return (unsigned long)match->data;
279 280
	}
#endif
281
	return id->driver_data;
282 283
}

284
static int sec_pmic_probe(struct i2c_client *i2c,
S
Sangbeom Kim 已提交
285 286
			    const struct i2c_device_id *id)
{
J
Jingoo Han 已提交
287
	struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
288
	const struct regmap_config *regmap;
289
	const struct mfd_cell *sec_devs;
290
	struct sec_pmic_dev *sec_pmic;
291
	unsigned long device_type;
292
	int ret, num_sec_devs;
S
Sangbeom Kim 已提交
293

294
	sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
295
				GFP_KERNEL);
296
	if (sec_pmic == NULL)
S
Sangbeom Kim 已提交
297 298
		return -ENOMEM;

299 300 301 302
	i2c_set_clientdata(i2c, sec_pmic);
	sec_pmic->dev = &i2c->dev;
	sec_pmic->i2c = i2c;
	sec_pmic->irq = i2c->irq;
303
	device_type = sec_i2c_get_driver_data(i2c, id);
304 305 306 307 308 309 310

	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;
		}
311
		pdata->device_type = device_type;
312
	}
S
Sangbeom Kim 已提交
313
	if (pdata) {
314 315 316 317
		sec_pmic->device_type = pdata->device_type;
		sec_pmic->ono = pdata->ono;
		sec_pmic->irq_base = pdata->irq_base;
		sec_pmic->wakeup = pdata->wakeup;
318
		sec_pmic->pdata = pdata;
S
Sangbeom Kim 已提交
319 320
	}

321
	switch (sec_pmic->device_type) {
322 323 324
	case S2MPA01:
		regmap = &s2mpa01_regmap_config;
		break;
325 326
	case S2MPS11X:
		regmap = &s2mps11_regmap_config;
327 328 329
		break;
	case S2MPS14X:
		regmap = &s2mps14_regmap_config;
330 331 332 333 334 335 336
		break;
	case S5M8763X:
		regmap = &s5m8763_regmap_config;
		break;
	case S5M8767X:
		regmap = &s5m8767_regmap_config;
		break;
337 338 339
	case S2MPU02:
		regmap = &s2mpu02_regmap_config;
		break;
340 341 342 343 344
	default:
		regmap = &sec_regmap_config;
		break;
	}

345 346 347
	sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap);
	if (IS_ERR(sec_pmic->regmap_pmic)) {
		ret = PTR_ERR(sec_pmic->regmap_pmic);
S
Sangbeom Kim 已提交
348
		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
349
			ret);
350
		return ret;
S
Sangbeom Kim 已提交
351 352
	}

353
	if (pdata && pdata->cfg_pmic_irq)
S
Sangbeom Kim 已提交
354 355
		pdata->cfg_pmic_irq();

356
	sec_irq_init(sec_pmic);
S
Sangbeom Kim 已提交
357

358
	pm_runtime_set_active(sec_pmic->dev);
S
Sangbeom Kim 已提交
359

360
	switch (sec_pmic->device_type) {
361
	case S5M8751X:
362 363
		sec_devs = s5m8751_devs;
		num_sec_devs = ARRAY_SIZE(s5m8751_devs);
364 365
		break;
	case S5M8763X:
366 367
		sec_devs = s5m8763_devs;
		num_sec_devs = ARRAY_SIZE(s5m8763_devs);
368 369
		break;
	case S5M8767X:
370 371
		sec_devs = s5m8767_devs;
		num_sec_devs = ARRAY_SIZE(s5m8767_devs);
372
		break;
373
	case S2MPA01:
374 375
		sec_devs = s2mpa01_devs;
		num_sec_devs = ARRAY_SIZE(s2mpa01_devs);
376
		break;
377
	case S2MPS11X:
378 379
		sec_devs = s2mps11_devs;
		num_sec_devs = ARRAY_SIZE(s2mps11_devs);
380
		break;
381
	case S2MPS14X:
382 383 384 385 386 387
		sec_devs = s2mps14_devs;
		num_sec_devs = ARRAY_SIZE(s2mps14_devs);
		break;
	case S2MPU02:
		sec_devs = s2mpu02_devs;
		num_sec_devs = ARRAY_SIZE(s2mpu02_devs);
388
		break;
389 390 391 392
	default:
		/* If this happens the probe function is problem */
		BUG();
	}
393 394
	ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL,
			      0, NULL);
395
	if (ret)
396
		goto err_mfd;
S
Sangbeom Kim 已提交
397

398 399
	device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);

S
Sangbeom Kim 已提交
400 401
	return ret;

402
err_mfd:
403
	sec_irq_exit(sec_pmic);
S
Sangbeom Kim 已提交
404 405 406
	return ret;
}

407
static int sec_pmic_remove(struct i2c_client *i2c)
S
Sangbeom Kim 已提交
408
{
409
	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
S
Sangbeom Kim 已提交
410

411 412
	mfd_remove_devices(sec_pmic->dev);
	sec_irq_exit(sec_pmic);
S
Sangbeom Kim 已提交
413 414 415
	return 0;
}

416
#ifdef CONFIG_PM_SLEEP
417 418 419 420 421
static int sec_pmic_suspend(struct device *dev)
{
	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);

422
	if (device_may_wakeup(dev))
423
		enable_irq_wake(sec_pmic->irq);
424 425 426 427 428 429 430 431 432 433
	/*
	 * 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);
434

435 436 437 438 439 440 441 442 443
	switch (sec_pmic->device_type) {
	case S2MPS14X:
	case S2MPU02:
		regulator_suspend_prepare(PM_SUSPEND_MEM);
		break;
	default:
		break;
	}

444 445 446 447 448 449 450 451
	return 0;
}

static int sec_pmic_resume(struct device *dev)
{
	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);

452
	if (device_may_wakeup(dev))
453
		disable_irq_wake(sec_pmic->irq);
454
	enable_irq(sec_pmic->irq);
455 456 457

	return 0;
}
458
#endif /* CONFIG_PM_SLEEP */
459 460 461

static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);

462 463
static const struct i2c_device_id sec_pmic_id[] = {
	{ "sec_pmic", 0 },
S
Sangbeom Kim 已提交
464 465
	{ }
};
466
MODULE_DEVICE_TABLE(i2c, sec_pmic_id);
S
Sangbeom Kim 已提交
467

468
static struct i2c_driver sec_pmic_driver = {
S
Sangbeom Kim 已提交
469
	.driver = {
470
		   .name = "sec_pmic",
S
Sangbeom Kim 已提交
471
		   .owner = THIS_MODULE,
472
		   .pm = &sec_pmic_pm_ops,
473
		   .of_match_table = of_match_ptr(sec_dt_match),
S
Sangbeom Kim 已提交
474
	},
475 476 477
	.probe = sec_pmic_probe,
	.remove = sec_pmic_remove,
	.id_table = sec_pmic_id,
S
Sangbeom Kim 已提交
478 479
};

480
static int __init sec_pmic_init(void)
S
Sangbeom Kim 已提交
481
{
482
	return i2c_add_driver(&sec_pmic_driver);
S
Sangbeom Kim 已提交
483 484
}

485
subsys_initcall(sec_pmic_init);
S
Sangbeom Kim 已提交
486

487
static void __exit sec_pmic_exit(void)
S
Sangbeom Kim 已提交
488
{
489
	i2c_del_driver(&sec_pmic_driver);
S
Sangbeom Kim 已提交
490
}
491
module_exit(sec_pmic_exit);
S
Sangbeom Kim 已提交
492 493 494 495

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