wm8350-core.c 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * wm8350-core.c  --  Device access for Wolfson WM8350
 *
 * Copyright 2007, 2008 Wolfson Microelectronics PLC.
 *
 * Author: Liam Girdwood, Mark Brown
 *
 *  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/kernel.h>
#include <linux/module.h>
17
#include <linux/slab.h>
M
Mark Brown 已提交
18
#include <linux/bug.h>
19 20 21
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
22
#include <linux/regmap.h>
M
Mark Brown 已提交
23
#include <linux/workqueue.h>
24 25 26

#include <linux/mfd/wm8350/core.h>
#include <linux/mfd/wm8350/audio.h>
M
Mark Brown 已提交
27
#include <linux/mfd/wm8350/comparator.h>
28 29
#include <linux/mfd/wm8350/gpio.h>
#include <linux/mfd/wm8350/pmic.h>
M
Mark Brown 已提交
30
#include <linux/mfd/wm8350/rtc.h>
31
#include <linux/mfd/wm8350/supply.h>
M
Mark Brown 已提交
32
#include <linux/mfd/wm8350/wdt.h>
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

#define WM8350_CLOCK_CONTROL_1		0x28
#define WM8350_AIF_TEST			0x74

/* debug */
#define WM8350_BUS_DEBUG 0
#if WM8350_BUS_DEBUG
#define dump(regs, src) do { \
	int i_; \
	u16 *src_ = src; \
	printk(KERN_DEBUG); \
	for (i_ = 0; i_ < regs; i_++) \
		printk(" 0x%4.4x", *src_++); \
	printk("\n"); \
} while (0);
#else
#define dump(bytes, src)
#endif

#define WM8350_LOCK_DEBUG 0
#if WM8350_LOCK_DEBUG
#define ldbg(format, arg...) printk(format, ## arg)
#else
#define ldbg(format, arg...)
#endif

/*
 * WM8350 Device IO
 */
static DEFINE_MUTEX(reg_lock_mutex);

/*
 * Safe read, modify, write methods
 */
int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
{
69
	return regmap_update_bits(wm8350->regmap, reg, mask, 0);
70 71 72 73 74
}
EXPORT_SYMBOL_GPL(wm8350_clear_bits);

int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
{
75
	return regmap_update_bits(wm8350->regmap, reg, mask, mask);
76 77 78 79 80
}
EXPORT_SYMBOL_GPL(wm8350_set_bits);

u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
{
81
	unsigned int data;
82 83
	int err;

84
	err = regmap_read(wm8350->regmap, reg, &data);
85 86 87 88 89 90 91 92 93 94 95
	if (err)
		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);

	return data;
}
EXPORT_SYMBOL_GPL(wm8350_reg_read);

int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
{
	int ret;

96 97
	ret = regmap_write(wm8350->regmap, reg, val);

98 99 100 101 102 103 104 105 106 107 108
	if (ret)
		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
	return ret;
}
EXPORT_SYMBOL_GPL(wm8350_reg_write);

int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
		      u16 *dest)
{
	int err = 0;

109
	err = regmap_bulk_read(wm8350->regmap, start_reg, dest, regs);
110 111 112
	if (err)
		dev_err(wm8350->dev, "block read starting from R%d failed\n",
			start_reg);
113

114 115 116 117 118 119 120 121 122
	return err;
}
EXPORT_SYMBOL_GPL(wm8350_block_read);

int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
		       u16 *src)
{
	int ret = 0;

123
	ret = regmap_bulk_write(wm8350->regmap, start_reg, src, regs);
124 125 126
	if (ret)
		dev_err(wm8350->dev, "block write starting at R%d failed\n",
			start_reg);
127

128 129 130 131
	return ret;
}
EXPORT_SYMBOL_GPL(wm8350_block_write);

132 133 134 135 136 137 138
/**
 * wm8350_reg_lock()
 *
 * The WM8350 has a hardware lock which can be used to prevent writes to
 * some registers (generally those which can cause particularly serious
 * problems if misused).  This function enables that lock.
 */
139 140 141 142
int wm8350_reg_lock(struct wm8350 *wm8350)
{
	int ret;

143 144
	mutex_lock(&reg_lock_mutex);

145
	ldbg(__func__);
146 147

	ret = wm8350_reg_write(wm8350, WM8350_SECURITY, WM8350_LOCK_KEY);
148 149
	if (ret)
		dev_err(wm8350->dev, "lock failed\n");
150 151 152 153 154

	wm8350->unlocked = false;

	mutex_unlock(&reg_lock_mutex);

155 156 157 158
	return ret;
}
EXPORT_SYMBOL_GPL(wm8350_reg_lock);

159 160 161 162 163 164 165 166 167
/**
 * wm8350_reg_unlock()
 *
 * The WM8350 has a hardware lock which can be used to prevent writes to
 * some registers (generally those which can cause particularly serious
 * problems if misused).  This function disables that lock so updates
 * can be performed.  For maximum safety this should be done only when
 * required.
 */
168 169 170 171
int wm8350_reg_unlock(struct wm8350 *wm8350)
{
	int ret;

172 173
	mutex_lock(&reg_lock_mutex);

174
	ldbg(__func__);
175 176

	ret = wm8350_reg_write(wm8350, WM8350_SECURITY, WM8350_UNLOCK_KEY);
177 178
	if (ret)
		dev_err(wm8350->dev, "unlock failed\n");
179 180 181 182 183

	wm8350->unlocked = true;

	mutex_unlock(&reg_lock_mutex);

184 185 186 187
	return ret;
}
EXPORT_SYMBOL_GPL(wm8350_reg_unlock);

M
Mark Brown 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
{
	u16 reg, result = 0;

	if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
		return -EINVAL;
	if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
	    && (scale != 0 || vref != 0))
		return -EINVAL;

	mutex_lock(&wm8350->auxadc_mutex);

	/* Turn on the ADC */
	reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
	wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);

	if (scale || vref) {
		reg = scale << 13;
		reg |= vref << 12;
		wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
	}

	reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
	reg |= 1 << channel | WM8350_AUXADC_POLL;
	wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);

214 215 216 217
	/* If a late IRQ left the completion signalled then consume
	 * the completion. */
	try_wait_for_completion(&wm8350->auxadc_done);

218 219 220 221
	/* We ignore the result of the completion and just check for a
	 * conversion result, allowing us to soldier on if the IRQ
	 * infrastructure is not set up for the chip. */
	wait_for_completion_timeout(&wm8350->auxadc_done, msecs_to_jiffies(5));
M
Mark Brown 已提交
222

223 224
	reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
	if (reg & WM8350_AUXADC_POLL)
M
Mark Brown 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
		dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
	else
		result = wm8350_reg_read(wm8350,
					 WM8350_AUX1_READBACK + channel);

	/* Turn off the ADC */
	reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
	wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
			 reg & ~WM8350_AUXADC_ENA);

	mutex_unlock(&wm8350->auxadc_mutex);

	return result & WM8350_AUXADC_DATA1_MASK;
}
EXPORT_SYMBOL_GPL(wm8350_read_auxadc);

241 242 243 244 245 246 247 248 249
static irqreturn_t wm8350_auxadc_irq(int irq, void *irq_data)
{
	struct wm8350 *wm8350 = irq_data;

	complete(&wm8350->auxadc_done);

	return IRQ_HANDLED;
}

250 251 252 253 254 255 256 257 258 259 260
/*
 * Register a client device.  This is non-fatal since there is no need to
 * fail the entire device init due to a single platform device failing.
 */
static void wm8350_client_dev_register(struct wm8350 *wm8350,
				       const char *name,
				       struct platform_device **pdev)
{
	int ret;

	*pdev = platform_device_alloc(name, -1);
261
	if (*pdev == NULL) {
262 263 264 265 266 267 268 269 270 271 272 273 274 275
		dev_err(wm8350->dev, "Failed to allocate %s\n", name);
		return;
	}

	(*pdev)->dev.parent = wm8350->dev;
	platform_set_drvdata(*pdev, wm8350);
	ret = platform_device_add(*pdev);
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
		platform_device_put(*pdev);
		*pdev = NULL;
	}
}

M
Mark Brown 已提交
276
int wm8350_device_init(struct wm8350 *wm8350, int irq,
277
		       struct wm8350_platform_data *pdata)
278
{
279
	int ret;
280 281
	unsigned int id1, id2, mask_rev;
	unsigned int cust_id, mode, chip_rev;
282

283 284
	dev_set_drvdata(wm8350->dev, wm8350);

285
	/* get WM8350 revision and config mode */
286
	ret = regmap_read(wm8350->regmap, WM8350_RESET_ID, &id1);
287 288 289 290 291
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
		goto err;
	}

292
	ret = regmap_read(wm8350->regmap, WM8350_ID, &id2);
293 294 295 296 297
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
		goto err;
	}

298
	ret = regmap_read(wm8350->regmap, WM8350_REVISION, &mask_rev);
299 300 301 302
	if (ret != 0) {
		dev_err(wm8350->dev, "Failed to read revision: %d\n", ret);
		goto err;
	}
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
	if (id1 != 0x6143) {
		dev_err(wm8350->dev,
			"Device with ID %x is not a WM8350\n", id1);
		ret = -ENODEV;
		goto err;
	}

	mode = id2 & WM8350_CONF_STS_MASK >> 10;
	cust_id = id2 & WM8350_CUST_ID_MASK;
	chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
	dev_info(wm8350->dev,
		 "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
		 mode, cust_id, mask_rev, chip_rev);

	if (cust_id != 0) {
		dev_err(wm8350->dev, "Unsupported CUST_ID\n");
		ret = -ENODEV;
		goto err;
	}

	switch (mask_rev) {
	case 0:
326 327 328
		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
		wm8350->pmic.max_isink = WM8350_ISINK_B;

329
		switch (chip_rev) {
330
		case WM8350_REV_E:
331
			dev_info(wm8350->dev, "WM8350 Rev E\n");
332 333
			break;
		case WM8350_REV_F:
334
			dev_info(wm8350->dev, "WM8350 Rev F\n");
335 336
			break;
		case WM8350_REV_G:
337
			dev_info(wm8350->dev, "WM8350 Rev G\n");
338
			wm8350->power.rev_g_coeff = 1;
339
			break;
M
Mark Brown 已提交
340
		case WM8350_REV_H:
341
			dev_info(wm8350->dev, "WM8350 Rev H\n");
342
			wm8350->power.rev_g_coeff = 1;
M
Mark Brown 已提交
343
			break;
344 345
		default:
			/* For safety we refuse to run on unknown hardware */
346
			dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
347 348 349
			ret = -ENODEV;
			goto err;
		}
350 351
		break;

M
Mark Brown 已提交
352 353 354 355 356 357 358 359 360 361
	case 1:
		wm8350->pmic.max_dcdc = WM8350_DCDC_4;
		wm8350->pmic.max_isink = WM8350_ISINK_A;

		switch (chip_rev) {
		case 0:
			dev_info(wm8350->dev, "WM8351 Rev A\n");
			wm8350->power.rev_g_coeff = 1;
			break;

362 363 364 365 366
		case 1:
			dev_info(wm8350->dev, "WM8351 Rev B\n");
			wm8350->power.rev_g_coeff = 1;
			break;

M
Mark Brown 已提交
367 368 369 370 371 372 373
		default:
			dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
			ret = -ENODEV;
			goto err;
		}
		break;

M
Mark Brown 已提交
374
	case 2:
375 376 377
		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
		wm8350->pmic.max_isink = WM8350_ISINK_B;

M
Mark Brown 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390
		switch (chip_rev) {
		case 0:
			dev_info(wm8350->dev, "WM8352 Rev A\n");
			wm8350->power.rev_g_coeff = 1;
			break;

		default:
			dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
			ret = -ENODEV;
			goto err;
		}
		break;

391 392
	default:
		dev_err(wm8350->dev, "Unknown MASK_REV\n");
393 394 395 396
		ret = -ENODEV;
		goto err;
	}

M
Mark Brown 已提交
397
	mutex_init(&wm8350->auxadc_mutex);
398
	init_completion(&wm8350->auxadc_done);
399

400 401
	ret = wm8350_irq_init(wm8350, irq, pdata);
	if (ret < 0)
402
		goto err;
M
Mark Brown 已提交
403

404 405 406 407 408 409 410 411 412 413
	if (wm8350->irq_base) {
		ret = request_threaded_irq(wm8350->irq_base +
					   WM8350_IRQ_AUXADC_DATARDY,
					   NULL, wm8350_auxadc_irq, 0,
					   "auxadc", wm8350);
		if (ret < 0)
			dev_warn(wm8350->dev,
				 "Failed to request AUXADC IRQ: %d\n", ret);
	}

414 415 416 417 418
	if (pdata && pdata->init) {
		ret = pdata->init(wm8350);
		if (ret != 0) {
			dev_err(wm8350->dev, "Platform init() failed: %d\n",
				ret);
419
			goto err_irq;
420 421 422
		}
	}

M
Mark Brown 已提交
423 424
	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);

425 426 427 428
	wm8350_client_dev_register(wm8350, "wm8350-codec",
				   &(wm8350->codec.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-gpio",
				   &(wm8350->gpio.pdev));
429 430
	wm8350_client_dev_register(wm8350, "wm8350-hwmon",
				   &(wm8350->hwmon.pdev));
431 432 433 434 435
	wm8350_client_dev_register(wm8350, "wm8350-power",
				   &(wm8350->power.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
	wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));

436 437
	return 0;

438 439
err_irq:
	wm8350_irq_exit(wm8350);
440
err:
441 442 443 444 445 446
	return ret;
}
EXPORT_SYMBOL_GPL(wm8350_device_init);

void wm8350_device_exit(struct wm8350 *wm8350)
{
447 448
	int i;

M
Mark Brown 已提交
449 450 451
	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++)
		platform_device_unregister(wm8350->pmic.led[i].pdev);

452
	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
453 454 455 456 457
		platform_device_unregister(wm8350->pmic.pdev[i]);

	platform_device_unregister(wm8350->wdt.pdev);
	platform_device_unregister(wm8350->rtc.pdev);
	platform_device_unregister(wm8350->power.pdev);
458
	platform_device_unregister(wm8350->hwmon.pdev);
459 460
	platform_device_unregister(wm8350->gpio.pdev);
	platform_device_unregister(wm8350->codec.pdev);
461

462 463 464
	if (wm8350->irq_base)
		free_irq(wm8350->irq_base + WM8350_IRQ_AUXADC_DATARDY, wm8350);

465
	wm8350_irq_exit(wm8350);
466 467 468
}
EXPORT_SYMBOL_GPL(wm8350_device_exit);

M
Mark Brown 已提交
469
MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
470
MODULE_LICENSE("GPL");