tc3589x.c 7.9 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
 * tc3589x_reg_read() - read a single TC3589x register
 * @tc3589x:	Device to read from
20 21
 * @reg:	Register to read
 */
22
int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
23 24 25
{
	int ret;

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

	return ret;
}
33
EXPORT_SYMBOL_GPL(tc3589x_reg_read);
34 35

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

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

	return ret;
}
52
EXPORT_SYMBOL_GPL(tc3589x_reg_write);
53 54

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

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

	return ret;
}
72
EXPORT_SYMBOL_GPL(tc3589x_block_read);
73 74

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

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

	return ret;
}
94
EXPORT_SYMBOL_GPL(tc3589x_block_write);
95 96

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

107
	mutex_lock(&tc3589x->lock);
108

109
	ret = tc3589x_reg_read(tc3589x, reg);
110 111 112 113 114 115
	if (ret < 0)
		goto out;

	ret &= ~mask;
	ret |= val;

116
	ret = tc3589x_reg_write(tc3589x, reg, ret);
117 118

out:
119
	mutex_unlock(&tc3589x->lock);
120 121
	return ret;
}
122
EXPORT_SYMBOL_GPL(tc3589x_set_bits);
123 124 125

static struct resource gpio_resources[] = {
	{
126 127
		.start	= TC3589x_INT_GPIIRQ,
		.end	= TC3589x_INT_GPIIRQ,
128 129 130 131
		.flags	= IORESOURCE_IRQ,
	},
};

132
static struct mfd_cell tc3589x_dev_gpio[] = {
133
	{
134
		.name		= "tc3589x-gpio",
135 136 137 138 139
		.num_resources	= ARRAY_SIZE(gpio_resources),
		.resources	= &gpio_resources[0],
	},
};

140
static irqreturn_t tc3589x_irq(int irq, void *data)
141
{
142
	struct tc3589x *tc3589x = data;
143 144
	int status;

145
again:
146
	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
147 148 149 150 151 152
	if (status < 0)
		return IRQ_NONE;

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

153
		handle_nested_irq(tc3589x->irq_base + bit);
154 155 156 157 158 159
		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
160 161
	 * effect. In such a case, recheck for any interrupt which is still
	 * pending.
162
	 */
163 164 165
	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
	if (status)
		goto again;
166 167 168 169

	return IRQ_HANDLED;
}

170
static void tc3589x_irq_dummy(unsigned int irq)
171 172 173 174
{
	/* No mask/unmask at this level */
}

175 176 177 178
static struct irq_chip tc3589x_irq_chip = {
	.name	= "tc3589x",
	.mask	= tc3589x_irq_dummy,
	.unmask	= tc3589x_irq_dummy,
179 180
};

181
static int tc3589x_irq_init(struct tc3589x *tc3589x)
182
{
183
	int base = tc3589x->irq_base;
184 185
	int irq;

186 187 188
	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
		set_irq_chip_data(irq, tc3589x);
		set_irq_chip_and_handler(irq, &tc3589x_irq_chip,
189 190 191 192 193 194 195 196 197 198 199 200
					 handle_edge_irq);
		set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
		set_irq_flags(irq, IRQF_VALID);
#else
		set_irq_noprobe(irq);
#endif
	}

	return 0;
}

201
static void tc3589x_irq_remove(struct tc3589x *tc3589x)
202
{
203
	int base = tc3589x->irq_base;
204 205
	int irq;

206
	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
207 208 209 210 211 212 213 214
#ifdef CONFIG_ARM
		set_irq_flags(irq, 0);
#endif
		set_irq_chip_and_handler(irq, NULL, NULL);
		set_irq_chip_data(irq, NULL);
	}
}

215
static int tc3589x_chip_init(struct tc3589x *tc3589x)
216 217 218
{
	int manf, ver, ret;

219
	manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
220 221 222
	if (manf < 0)
		return manf;

223
	ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
224 225 226
	if (ver < 0)
		return ver;

227 228
	if (manf != TC3589x_MANFCODE_MAGIC) {
		dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
229 230 231
		return -EINVAL;
	}

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

	/* Put everything except the IRQ module into reset */
235 236 237 238 239
	ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
				TC3589x_RSTCTRL_TIMRST
				| TC3589x_RSTCTRL_ROTRST
				| TC3589x_RSTCTRL_KBDRST
				| TC3589x_RSTCTRL_GPIRST);
240 241 242 243
	if (ret < 0)
		return ret;

	/* Clear the reset interrupt. */
244
	return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
245 246
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
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");
	}

	return ret;

}

267
static int __devinit tc3589x_probe(struct i2c_client *i2c,
268 269
				   const struct i2c_device_id *id)
{
270 271
	struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
	struct tc3589x *tc3589x;
272 273 274 275 276 277
	int ret;

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

278 279
	tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL);
	if (!tc3589x)
280 281
		return -ENOMEM;

282
	mutex_init(&tc3589x->lock);
283

284 285 286 287 288
	tc3589x->dev = &i2c->dev;
	tc3589x->i2c = i2c;
	tc3589x->pdata = pdata;
	tc3589x->irq_base = pdata->irq_base;
	tc3589x->num_gpio = id->driver_data;
289

290
	i2c_set_clientdata(i2c, tc3589x);
291

292
	ret = tc3589x_chip_init(tc3589x);
293 294 295
	if (ret)
		goto out_free;

296
	ret = tc3589x_irq_init(tc3589x);
297 298 299
	if (ret)
		goto out_free;

300
	ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
301
				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
302
				   "tc3589x", tc3589x);
303
	if (ret) {
304
		dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
305 306 307
		goto out_removeirq;
	}

308
	ret = tc3589x_device_init(tc3589x);
309
	if (ret) {
310
		dev_err(tc3589x->dev, "failed to add child devices\n");
311 312 313 314 315 316
		goto out_freeirq;
	}

	return 0;

out_freeirq:
317
	free_irq(tc3589x->i2c->irq, tc3589x);
318
out_removeirq:
319
	tc3589x_irq_remove(tc3589x);
320
out_free:
321
	kfree(tc3589x);
322 323 324
	return ret;
}

325
static int __devexit tc3589x_remove(struct i2c_client *client)
326
{
327
	struct tc3589x *tc3589x = i2c_get_clientdata(client);
328

329
	mfd_remove_devices(tc3589x->dev);
330

331 332
	free_irq(tc3589x->i2c->irq, tc3589x);
	tc3589x_irq_remove(tc3589x);
333

334
	kfree(tc3589x);
335 336 337 338

	return 0;
}

339 340
static const struct i2c_device_id tc3589x_id[] = {
	{ "tc3589x", 24 },
341 342
	{ }
};
343
MODULE_DEVICE_TABLE(i2c, tc3589x_id);
344

345 346
static struct i2c_driver tc3589x_driver = {
	.driver.name	= "tc3589x",
347
	.driver.owner	= THIS_MODULE,
348 349 350
	.probe		= tc3589x_probe,
	.remove		= __devexit_p(tc3589x_remove),
	.id_table	= tc3589x_id,
351 352
};

353
static int __init tc3589x_init(void)
354
{
355
	return i2c_add_driver(&tc3589x_driver);
356
}
357
subsys_initcall(tc3589x_init);
358

359
static void __exit tc3589x_exit(void)
360
{
361
	i2c_del_driver(&tc3589x_driver);
362
}
363
module_exit(tc3589x_exit);
364 365

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