ab8500-gpadc.c 8.9 KB
Newer Older
A
Arun Murthy 已提交
1 2 3 4 5
/*
 * Copyright (C) ST-Ericsson SA 2010
 *
 * License Terms: GNU General Public License v2
 * Author: Arun R Murthy <arun.murthy@stericsson.com>
6
 * Author: Daniel Willerud <daniel.willerud@stericsson.com>
A
Arun Murthy 已提交
7 8 9 10 11 12 13 14 15 16 17 18
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/slab.h>
19
#include <linux/list.h>
A
Arun Murthy 已提交
20 21
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
22
#include <linux/mfd/ab8500/ab8500-gpadc.h>
A
Arun Murthy 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

/*
 * GPADC register offsets
 * Bank : 0x0A
 */
#define AB8500_GPADC_CTRL1_REG		0x00
#define AB8500_GPADC_CTRL2_REG		0x01
#define AB8500_GPADC_CTRL3_REG		0x02
#define AB8500_GPADC_AUTO_TIMER_REG	0x03
#define AB8500_GPADC_STAT_REG		0x04
#define AB8500_GPADC_MANDATAL_REG	0x05
#define AB8500_GPADC_MANDATAH_REG	0x06
#define AB8500_GPADC_AUTODATAL_REG	0x07
#define AB8500_GPADC_AUTODATAH_REG	0x08
#define AB8500_GPADC_MUX_CTRL_REG	0x09

/* gpadc constants */
#define EN_VINTCORE12			0x04
#define EN_VTVOUT			0x02
#define EN_GPADC			0x01
#define DIS_GPADC			0x00
#define SW_AVG_16			0x60
#define ADC_SW_CONV			0x04
#define EN_BUF				0x40
#define DIS_ZERO			0x00
#define GPADC_BUSY			0x01

/**
 * struct ab8500_gpadc - ab8500 GPADC device information
 * @dev:			pointer to the struct device
53 54
 * @node:			a list of AB8500 GPADCs, hence prepared for
				reentrance
A
Arun Murthy 已提交
55 56 57 58 59 60
 * @ab8500_gpadc_complete:	pointer to the struct completion, to indicate
 *				the completion of gpadc conversion
 * @ab8500_gpadc_lock:		structure of type mutex
 * @regu:			pointer to the struct regulator
 * @irq:			interrupt number that is used by gpadc
 */
61
struct ab8500_gpadc {
A
Arun Murthy 已提交
62
	struct device *dev;
63
	struct list_head node;
A
Arun Murthy 已提交
64 65 66 67
	struct completion ab8500_gpadc_complete;
	struct mutex ab8500_gpadc_lock;
	struct regulator *regu;
	int irq;
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
};

static LIST_HEAD(ab8500_gpadc_list);

/**
 * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC
 * (i.e. the first GPADC in the instance list)
 */
struct ab8500_gpadc *ab8500_gpadc_get(char *name)
{
	struct ab8500_gpadc *gpadc;

	list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
		if (!strcmp(name, dev_name(gpadc->dev)))
		    return gpadc;
	}

	return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(ab8500_gpadc_get);
A
Arun Murthy 已提交
88 89 90 91 92 93 94 95 96

/**
 * ab8500_gpadc_convert() - gpadc conversion
 * @input:	analog input to be converted to digital data
 *
 * This function converts the selected analog i/p to digital
 * data. Thereafter calibration has to be made to obtain the
 * data in the required quantity measurement.
 */
97
int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
A
Arun Murthy 已提交
98 99 100 101 102 103
{
	int ret;
	u16 data = 0;
	int looplimit = 0;
	u8 val, low_data, high_data;

104
	if (!gpadc)
A
Arun Murthy 已提交
105 106
		return -ENODEV;

107
	mutex_lock(&gpadc->ab8500_gpadc_lock);
A
Arun Murthy 已提交
108
	/* Enable VTVout LDO this is required for GPADC */
109
	regulator_enable(gpadc->regu);
A
Arun Murthy 已提交
110 111 112

	/* Check if ADC is not busy, lock and proceed */
	do {
113 114
		ret = abx500_get_register_interruptible(gpadc->dev,
			AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
A
Arun Murthy 已提交
115 116 117 118 119 120 121
		if (ret < 0)
			goto out;
		if (!(val & GPADC_BUSY))
			break;
		msleep(10);
	} while (++looplimit < 10);
	if (looplimit >= 10 && (val & GPADC_BUSY)) {
122
		dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
A
Arun Murthy 已提交
123 124 125 126 127
		ret = -EINVAL;
		goto out;
	}

	/* Enable GPADC */
128 129
	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
A
Arun Murthy 已提交
130
	if (ret < 0) {
131
		dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
A
Arun Murthy 已提交
132 133 134
		goto out;
	}
	/* Select the input source and set average samples to 16 */
135
	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
A
Arun Murthy 已提交
136 137
		AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
	if (ret < 0) {
138
		dev_err(gpadc->dev,
A
Arun Murthy 已提交
139 140 141 142
			"gpadc_conversion: set avg samples failed\n");
		goto out;
	}
	/* Enable ADC, Buffering and select rising edge, start Conversion */
143 144
	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
A
Arun Murthy 已提交
145
	if (ret < 0) {
146
		dev_err(gpadc->dev,
A
Arun Murthy 已提交
147 148 149
			"gpadc_conversion: select falling edge failed\n");
		goto out;
	}
150 151
	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
A
Arun Murthy 已提交
152
	if (ret < 0) {
153
		dev_err(gpadc->dev,
A
Arun Murthy 已提交
154 155 156 157
			"gpadc_conversion: start s/w conversion failed\n");
		goto out;
	}
	/* wait for completion of conversion */
158 159
	if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
		dev_err(gpadc->dev,
A
Arun Murthy 已提交
160 161 162 163 164 165
			"timeout: didnt recieve GPADC conversion interrupt\n");
		ret = -EINVAL;
		goto out;
	}

	/* Read the converted RAW data */
166
	ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
A
Arun Murthy 已提交
167 168
		AB8500_GPADC_MANDATAL_REG, &low_data);
	if (ret < 0) {
169
		dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
A
Arun Murthy 已提交
170 171 172
		goto out;
	}

173
	ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
A
Arun Murthy 已提交
174 175
		AB8500_GPADC_MANDATAH_REG, &high_data);
	if (ret < 0) {
176 177
		dev_err(gpadc->dev,
			"gpadc_conversion: read high data failed\n");
A
Arun Murthy 已提交
178 179 180 181 182
		goto out;
	}

	data = (high_data << 8) | low_data;
	/* Disable GPADC */
183
	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
A
Arun Murthy 已提交
184 185
		AB8500_GPADC_CTRL1_REG, DIS_GPADC);
	if (ret < 0) {
186
		dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
A
Arun Murthy 已提交
187 188 189
		goto out;
	}
	/* Disable VTVout LDO this is required for GPADC */
190 191
	regulator_disable(gpadc->regu);
	mutex_unlock(&gpadc->ab8500_gpadc_lock);
A
Arun Murthy 已提交
192 193 194 195 196 197 198 199 200
	return data;

out:
	/*
	 * It has shown to be needed to turn off the GPADC if an error occurs,
	 * otherwise we might have problem when waiting for the busy bit in the
	 * GPADC status register to go low. In V1.1 there wait_for_completion
	 * seems to timeout when waiting for an interrupt.. Not seen in V2.0
	 */
201
	(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
A
Arun Murthy 已提交
202
		AB8500_GPADC_CTRL1_REG, DIS_GPADC);
203 204 205 206
	regulator_disable(gpadc->regu);
	mutex_unlock(&gpadc->ab8500_gpadc_lock);
	dev_err(gpadc->dev,
		"gpadc_conversion: Failed to AD convert channel %d\n", input);
A
Arun Murthy 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220
	return ret;
}
EXPORT_SYMBOL(ab8500_gpadc_convert);

/**
 * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
 * @irq:	irq number
 * @data:	pointer to the data passed during request irq
 *
 * This is a interrupt service routine for s/w gpadc conversion completion.
 * Notifies the gpadc completion is completed and the converted raw value
 * can be read from the registers.
 * Returns IRQ status(IRQ_HANDLED)
 */
221
static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
A
Arun Murthy 已提交
222
{
223
	struct ab8500_gpadc *gpadc = _gpadc;
A
Arun Murthy 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

	complete(&gpadc->ab8500_gpadc_complete);

	return IRQ_HANDLED;
}

static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct ab8500_gpadc *gpadc;

	gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
	if (!gpadc) {
		dev_err(&pdev->dev, "Error: No memory\n");
		return -ENOMEM;
	}

	gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
	if (gpadc->irq < 0) {
243 244
		dev_err(gpadc->dev, "failed to get platform irq-%d\n",
			gpadc->irq);
A
Arun Murthy 已提交
245 246 247 248 249
		ret = gpadc->irq;
		goto fail;
	}

	gpadc->dev = &pdev->dev;
250
	mutex_init(&gpadc->ab8500_gpadc_lock);
A
Arun Murthy 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

	/* Initialize completion used to notify completion of conversion */
	init_completion(&gpadc->ab8500_gpadc_complete);

	/* Register interrupt  - SwAdcComplete */
	ret = request_threaded_irq(gpadc->irq, NULL,
		ab8500_bm_gpswadcconvend_handler,
		IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc);
	if (ret < 0) {
		dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
			gpadc->irq);
		goto fail;
	}

	/* VTVout LDO used to power up ab8500-GPADC */
	gpadc->regu = regulator_get(&pdev->dev, "vddadc");
	if (IS_ERR(gpadc->regu)) {
		ret = PTR_ERR(gpadc->regu);
		dev_err(gpadc->dev, "failed to get vtvout LDO\n");
270
		goto fail_irq;
A
Arun Murthy 已提交
271
	}
272
	list_add_tail(&gpadc->node, &ab8500_gpadc_list);
A
Arun Murthy 已提交
273 274
	dev_dbg(gpadc->dev, "probe success\n");
	return 0;
275 276
fail_irq:
	free_irq(gpadc->irq, gpadc);
A
Arun Murthy 已提交
277 278 279 280 281 282 283 284 285 286
fail:
	kfree(gpadc);
	gpadc = NULL;
	return ret;
}

static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
{
	struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev);

287 288
	/* remove this gpadc entry from the list */
	list_del(&gpadc->node);
A
Arun Murthy 已提交
289
	/* remove interrupt  - completion of Sw ADC conversion */
290
	free_irq(gpadc->irq, gpadc);
A
Arun Murthy 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	/* disable VTVout LDO that is being used by GPADC */
	regulator_put(gpadc->regu);
	kfree(gpadc);
	gpadc = NULL;
	return 0;
}

static struct platform_driver ab8500_gpadc_driver = {
	.probe = ab8500_gpadc_probe,
	.remove = __devexit_p(ab8500_gpadc_remove),
	.driver = {
		.name = "ab8500-gpadc",
		.owner = THIS_MODULE,
	},
};

static int __init ab8500_gpadc_init(void)
{
	return platform_driver_register(&ab8500_gpadc_driver);
}

static void __exit ab8500_gpadc_exit(void)
{
	platform_driver_unregister(&ab8500_gpadc_driver);
}

subsys_initcall_sync(ab8500_gpadc_init);
module_exit(ab8500_gpadc_exit);

MODULE_LICENSE("GPL v2");
321
MODULE_AUTHOR("Arun R Murthy, Daniel Willerud");
A
Arun Murthy 已提交
322 323
MODULE_ALIAS("platform:ab8500_gpadc");
MODULE_DESCRIPTION("AB8500 GPADC driver");