cregit-Linux how code gets into the kernel

Release 4.14 drivers/mfd/wm831x-auxadc.c

Directory: drivers/mfd
/*
 * wm831x-auxadc.c  --  AUXADC for Wolfson WM831x PMICs
 *
 * Copyright 2009-2011 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/list.h>

#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/irq.h>
#include <linux/mfd/wm831x/auxadc.h>
#include <linux/mfd/wm831x/otp.h>
#include <linux/mfd/wm831x/regulator.h>


struct wm831x_auxadc_req {
	
struct list_head list;
	
enum wm831x_auxadc input;
	
int val;
	
struct completion done;
};


static int wm831x_auxadc_read_irq(struct wm831x *wm831x, enum wm831x_auxadc input) { struct wm831x_auxadc_req *req; int ret; bool ena = false; req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; init_completion(&req->done); req->input = input; req->val = -ETIMEDOUT; mutex_lock(&wm831x->auxadc_lock); /* Enqueue the request */ list_add(&req->list, &wm831x->auxadc_pending); ena = !wm831x->auxadc_active; if (ena) { ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, WM831X_AUX_ENA); if (ret != 0) { dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); goto out; } } /* Enable the conversion if not already running */ if (!(wm831x->auxadc_active & (1 << input))) { ret = wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE, 1 << input, 1 << input); if (ret != 0) { dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); goto out; } wm831x->auxadc_active |= 1 << input; } /* We convert at the fastest rate possible */ if (ena) { ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_CVT_ENA | WM831X_AUX_RATE_MASK, WM831X_AUX_CVT_ENA | WM831X_AUX_RATE_MASK); if (ret != 0) { dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); goto out; } } mutex_unlock(&wm831x->auxadc_lock); /* Wait for an interrupt */ wait_for_completion_timeout(&req->done, msecs_to_jiffies(500)); mutex_lock(&wm831x->auxadc_lock); list_del(&req->list); ret = req->val; out: mutex_unlock(&wm831x->auxadc_lock); kfree(req); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown314100.00%1100.00%
Total314100.00%1100.00%


static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) { struct wm831x *wm831x = irq_data; struct wm831x_auxadc_req *req; int ret, input, val; ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); if (ret < 0) { dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret); return IRQ_NONE; } input = ((ret & WM831X_AUX_DATA_SRC_MASK) >> WM831X_AUX_DATA_SRC_SHIFT) - 1; if (input == 14) input = WM831X_AUX_CAL; val = ret & WM831X_AUX_DATA_MASK; mutex_lock(&wm831x->auxadc_lock); /* Disable this conversion, we're about to complete all users */ wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE, 1 << input, 0); wm831x->auxadc_active &= ~(1 << input); /* Turn off the entire convertor if idle */ if (!wm831x->auxadc_active) wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0); /* Wake up any threads waiting for this request */ list_for_each_entry(req, &wm831x->auxadc_pending, list) { if (req->input == input) { req->val = val; complete(&req->done); } } mutex_unlock(&wm831x->auxadc_lock); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown189100.00%1100.00%
Total189100.00%1100.00%


static int wm831x_auxadc_read_polled(struct wm831x *wm831x, enum wm831x_auxadc input) { int ret, src, timeout; mutex_lock(&wm831x->auxadc_lock); ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, WM831X_AUX_ENA); if (ret < 0) { dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); goto out; } /* We force a single source at present */ src = input; ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, 1 << src); if (ret < 0) { dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); goto out; } ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); if (ret < 0) { dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); goto disable; } /* If we're not using interrupts then poll the * interrupt status register */ timeout = 5; while (timeout) { msleep(1); ret = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1); if (ret < 0) { dev_err(wm831x->dev, "ISR 1 read failed: %d\n", ret); goto disable; } /* Did it complete? */ if (ret & WM831X_AUXADC_DATA_EINT) { wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_AUXADC_DATA_EINT); break; } else { dev_err(wm831x->dev, "AUXADC conversion timeout\n"); ret = -EBUSY; goto disable; } } ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); if (ret < 0) { dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret); goto disable; } src = ((ret & WM831X_AUX_DATA_SRC_MASK) >> WM831X_AUX_DATA_SRC_SHIFT) - 1; if (src == 14) src = WM831X_AUX_CAL; if (src != input) { dev_err(wm831x->dev, "Data from source %d not %d\n", src, input); ret = -EINVAL; } else { ret &= WM831X_AUX_DATA_MASK; } disable: wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); out: mutex_unlock(&wm831x->auxadc_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown340100.00%2100.00%
Total340100.00%2100.00%

/** * wm831x_auxadc_read: Read a value from the WM831x AUXADC * * @wm831x: Device to read from. * @input: AUXADC input to read. */
int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) { return wm831x->auxadc_read(wm831x, input); }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown24100.00%2100.00%
Total24100.00%2100.00%

EXPORT_SYMBOL_GPL(wm831x_auxadc_read); /** * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC * * @wm831x: Device to read from. * @input: AUXADC input to read. */
int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) { int ret; ret = wm831x_auxadc_read(wm831x, input); if (ret < 0) return ret; ret *= 1465; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown42100.00%1100.00%
Total42100.00%1100.00%

EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
void wm831x_auxadc_init(struct wm831x *wm831x) { int ret; mutex_init(&wm831x->auxadc_lock); INIT_LIST_HEAD(&wm831x->auxadc_pending); if (wm831x->irq) { wm831x->auxadc_read = wm831x_auxadc_read_irq; ret = request_threaded_irq(wm831x_irq(wm831x, WM831X_IRQ_AUXADC_DATA), NULL, wm831x_auxadc_irq, IRQF_ONESHOT, "auxadc", wm831x); if (ret < 0) { dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", ret); wm831x->auxadc_read = NULL; } } if (!wm831x->auxadc_read) wm831x->auxadc_read = wm831x_auxadc_read_polled; }

Contributors

PersonTokensPropCommitsCommitProp
Mark Brown10299.03%375.00%
Fabio Estevam10.97%125.00%
Total103100.00%4100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Mark Brown108099.91%375.00%
Fabio Estevam10.09%125.00%
Total1081100.00%4100.00%
Directory: drivers/mfd
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.