tc3589x.c 9.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (C) ST-Ericsson SA 2010
 *
 * License Terms: GNU General Public License, version 2
 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
 */

#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
15
#include <linux/mfd/tc3589x.h>
16

17 18 19
#define TC3589x_CLKMODE_MODCTL_SLEEP		0x0
#define TC3589x_CLKMODE_MODCTL_OPERATION	(1 << 0)

20
/**
21 22
 * tc3589x_reg_read() - read a single TC3589x register
 * @tc3589x:	Device to read from
23 24
 * @reg:	Register to read
 */
25
int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
26 27 28
{
	int ret;

29
	ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
30
	if (ret < 0)
31
		dev_err(tc3589x->dev, "failed to read reg %#x: %d\n",
32 33 34 35
			reg, ret);

	return ret;
}
36
EXPORT_SYMBOL_GPL(tc3589x_reg_read);
37 38

/**
39 40
 * tc3589x_reg_read() - write a single TC3589x register
 * @tc3589x:	Device to write to
41 42 43
 * @reg:	Register to read
 * @data:	Value to write
 */
44
int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
45 46 47
{
	int ret;

48
	ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
49
	if (ret < 0)
50
		dev_err(tc3589x->dev, "failed to write reg %#x: %d\n",
51 52 53 54
			reg, ret);

	return ret;
}
55
EXPORT_SYMBOL_GPL(tc3589x_reg_write);
56 57

/**
58 59
 * tc3589x_block_read() - read multiple TC3589x registers
 * @tc3589x:	Device to read from
60 61 62 63
 * @reg:	First register
 * @length:	Number of registers
 * @values:	Buffer to write to
 */
64
int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
65 66 67
{
	int ret;

68
	ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
69
	if (ret < 0)
70
		dev_err(tc3589x->dev, "failed to read regs %#x: %d\n",
71 72 73 74
			reg, ret);

	return ret;
}
75
EXPORT_SYMBOL_GPL(tc3589x_block_read);
76 77

/**
78 79
 * tc3589x_block_write() - write multiple TC3589x registers
 * @tc3589x:	Device to write to
80 81 82 83
 * @reg:	First register
 * @length:	Number of registers
 * @values:	Values to write
 */
84
int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
85 86 87 88
			const u8 *values)
{
	int ret;

89
	ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
90 91
					     values);
	if (ret < 0)
92
		dev_err(tc3589x->dev, "failed to write regs %#x: %d\n",
93 94 95 96
			reg, ret);

	return ret;
}
97
EXPORT_SYMBOL_GPL(tc3589x_block_write);
98 99

/**
100 101
 * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register
 * @tc3589x:	Device to write to
102 103 104 105
 * @reg:	Register to write
 * @mask:	Mask of bits to set
 * @values:	Value to set
 */
106
int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
107 108 109
{
	int ret;

110
	mutex_lock(&tc3589x->lock);
111

112
	ret = tc3589x_reg_read(tc3589x, reg);
113 114 115 116 117 118
	if (ret < 0)
		goto out;

	ret &= ~mask;
	ret |= val;

119
	ret = tc3589x_reg_write(tc3589x, reg, ret);
120 121

out:
122
	mutex_unlock(&tc3589x->lock);
123 124
	return ret;
}
125
EXPORT_SYMBOL_GPL(tc3589x_set_bits);
126 127 128

static struct resource gpio_resources[] = {
	{
129 130
		.start	= TC3589x_INT_GPIIRQ,
		.end	= TC3589x_INT_GPIIRQ,
131 132 133 134
		.flags	= IORESOURCE_IRQ,
	},
};

135 136 137 138 139 140 141 142
static struct resource keypad_resources[] = {
	{
		.start  = TC3589x_INT_KBDIRQ,
		.end    = TC3589x_INT_KBDIRQ,
		.flags  = IORESOURCE_IRQ,
	},
};

143
static struct mfd_cell tc3589x_dev_gpio[] = {
144
	{
145
		.name		= "tc3589x-gpio",
146 147 148 149 150
		.num_resources	= ARRAY_SIZE(gpio_resources),
		.resources	= &gpio_resources[0],
	},
};

151 152 153 154 155 156 157 158
static struct mfd_cell tc3589x_dev_keypad[] = {
	{
		.name           = "tc3589x-keypad",
		.num_resources  = ARRAY_SIZE(keypad_resources),
		.resources      = &keypad_resources[0],
	},
};

159
static irqreturn_t tc3589x_irq(int irq, void *data)
160
{
161
	struct tc3589x *tc3589x = data;
162 163
	int status;

164
again:
165
	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
166 167 168 169 170 171
	if (status < 0)
		return IRQ_NONE;

	while (status) {
		int bit = __ffs(status);

172
		handle_nested_irq(tc3589x->irq_base + bit);
173 174 175 176 177 178
		status &= ~(1 << bit);
	}

	/*
	 * A dummy read or write (to any register) appears to be necessary to
	 * have the last interrupt clear (for example, GPIO IC write) take
179 180
	 * effect. In such a case, recheck for any interrupt which is still
	 * pending.
181
	 */
182 183 184
	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
	if (status)
		goto again;
185 186 187 188

	return IRQ_HANDLED;
}

189
static int tc3589x_irq_init(struct tc3589x *tc3589x)
190
{
191
	int base = tc3589x->irq_base;
192 193
	int irq;

194
	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
T
Thomas Gleixner 已提交
195 196
		irq_set_chip_data(irq, tc3589x);
		irq_set_chip_and_handler(irq, &dummy_irq_chip,
197
					 handle_edge_irq);
T
Thomas Gleixner 已提交
198
		irq_set_nested_thread(irq, 1);
199 200 201
#ifdef CONFIG_ARM
		set_irq_flags(irq, IRQF_VALID);
#else
T
Thomas Gleixner 已提交
202
		irq_set_noprobe(irq);
203 204 205 206 207 208
#endif
	}

	return 0;
}

209
static void tc3589x_irq_remove(struct tc3589x *tc3589x)
210
{
211
	int base = tc3589x->irq_base;
212 213
	int irq;

214
	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
215 216 217
#ifdef CONFIG_ARM
		set_irq_flags(irq, 0);
#endif
T
Thomas Gleixner 已提交
218 219
		irq_set_chip_and_handler(irq, NULL, NULL);
		irq_set_chip_data(irq, NULL);
220 221 222
	}
}

223
static int tc3589x_chip_init(struct tc3589x *tc3589x)
224 225 226
{
	int manf, ver, ret;

227
	manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
228 229 230
	if (manf < 0)
		return manf;

231
	ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
232 233 234
	if (ver < 0)
		return ver;

235 236
	if (manf != TC3589x_MANFCODE_MAGIC) {
		dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
237 238 239
		return -EINVAL;
	}

240
	dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
241

242 243 244 245 246
	/*
	 * Put everything except the IRQ module into reset;
	 * also spare the GPIO module for any pin initialization
	 * done during pre-kernel boot
	 */
247 248 249
	ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
				TC3589x_RSTCTRL_TIMRST
				| TC3589x_RSTCTRL_ROTRST
250
				| TC3589x_RSTCTRL_KBDRST);
251 252 253 254
	if (ret < 0)
		return ret;

	/* Clear the reset interrupt. */
255
	return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
256 257
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
{
	int ret = 0;
	unsigned int blocks = tc3589x->pdata->block;

	if (blocks & TC3589x_BLOCK_GPIO) {
		ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
				ARRAY_SIZE(tc3589x_dev_gpio), NULL,
				tc3589x->irq_base);
		if (ret) {
			dev_err(tc3589x->dev, "failed to add gpio child\n");
			return ret;
		}
		dev_info(tc3589x->dev, "added gpio block\n");
	}

274 275 276 277 278 279 280 281 282 283
	if (blocks & TC3589x_BLOCK_KEYPAD) {
		ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
				ARRAY_SIZE(tc3589x_dev_keypad), NULL,
				tc3589x->irq_base);
		if (ret) {
			dev_err(tc3589x->dev, "failed to keypad child\n");
			return ret;
		}
		dev_info(tc3589x->dev, "added keypad block\n");
	}
284

285
	return ret;
286 287
}

288
static int __devinit tc3589x_probe(struct i2c_client *i2c,
289 290
				   const struct i2c_device_id *id)
{
291 292
	struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
	struct tc3589x *tc3589x;
293 294 295 296 297 298
	int ret;

	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
				     | I2C_FUNC_SMBUS_I2C_BLOCK))
		return -EIO;

299 300
	tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL);
	if (!tc3589x)
301 302
		return -ENOMEM;

303
	mutex_init(&tc3589x->lock);
304

305 306 307 308 309
	tc3589x->dev = &i2c->dev;
	tc3589x->i2c = i2c;
	tc3589x->pdata = pdata;
	tc3589x->irq_base = pdata->irq_base;
	tc3589x->num_gpio = id->driver_data;
310

311
	i2c_set_clientdata(i2c, tc3589x);
312

313
	ret = tc3589x_chip_init(tc3589x);
314 315 316
	if (ret)
		goto out_free;

317
	ret = tc3589x_irq_init(tc3589x);
318 319 320
	if (ret)
		goto out_free;

321
	ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
322
				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
323
				   "tc3589x", tc3589x);
324
	if (ret) {
325
		dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
326 327 328
		goto out_removeirq;
	}

329
	ret = tc3589x_device_init(tc3589x);
330
	if (ret) {
331
		dev_err(tc3589x->dev, "failed to add child devices\n");
332 333 334 335 336 337
		goto out_freeirq;
	}

	return 0;

out_freeirq:
338
	free_irq(tc3589x->i2c->irq, tc3589x);
339
out_removeirq:
340
	tc3589x_irq_remove(tc3589x);
341
out_free:
342
	kfree(tc3589x);
343 344 345
	return ret;
}

346
static int __devexit tc3589x_remove(struct i2c_client *client)
347
{
348
	struct tc3589x *tc3589x = i2c_get_clientdata(client);
349

350
	mfd_remove_devices(tc3589x->dev);
351

352 353
	free_irq(tc3589x->i2c->irq, tc3589x);
	tc3589x_irq_remove(tc3589x);
354

355
	kfree(tc3589x);
356 357 358 359

	return 0;
}

360
#ifdef CONFIG_PM
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
static int tc3589x_suspend(struct device *dev)
{
	struct tc3589x *tc3589x = dev_get_drvdata(dev);
	struct i2c_client *client = tc3589x->i2c;
	int ret = 0;

	/* put the system to sleep mode */
	if (!device_may_wakeup(&client->dev))
		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
				TC3589x_CLKMODE_MODCTL_SLEEP);

	return ret;
}

static int tc3589x_resume(struct device *dev)
{
	struct tc3589x *tc3589x = dev_get_drvdata(dev);
	struct i2c_client *client = tc3589x->i2c;
	int ret = 0;

	/* enable the system into operation */
	if (!device_may_wakeup(&client->dev))
		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
				TC3589x_CLKMODE_MODCTL_OPERATION);

	return ret;
}

static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend,
						tc3589x_resume);
391
#endif
392

393 394
static const struct i2c_device_id tc3589x_id[] = {
	{ "tc3589x", 24 },
395 396
	{ }
};
397
MODULE_DEVICE_TABLE(i2c, tc3589x_id);
398

399 400
static struct i2c_driver tc3589x_driver = {
	.driver.name	= "tc3589x",
401
	.driver.owner	= THIS_MODULE,
402 403 404
#ifdef CONFIG_PM
	.driver.pm	= &tc3589x_dev_pm_ops,
#endif
405 406 407
	.probe		= tc3589x_probe,
	.remove		= __devexit_p(tc3589x_remove),
	.id_table	= tc3589x_id,
408 409
};

410
static int __init tc3589x_init(void)
411
{
412
	return i2c_add_driver(&tc3589x_driver);
413
}
414
subsys_initcall(tc3589x_init);
415

416
static void __exit tc3589x_exit(void)
417
{
418
	i2c_del_driver(&tc3589x_driver);
419
}
420
module_exit(tc3589x_exit);
421 422

MODULE_LICENSE("GPL v2");
423
MODULE_DESCRIPTION("TC3589x MFD core driver");
424
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");