[go: nahoru, domu]

10b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi/*
24fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi * MFD driver for twl4030 audio submodule, which contains an audio codec, and
34fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi * the vibra control.
40b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
54a7c00cd94d4ca7061c481fe823a256e37436044Peter Ujfalusi * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
60b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
70b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * Copyright:   (C) 2009 Nokia Corporation
80b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
90b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * This program is free software; you can redistribute it and/or modify
100b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * it under the terms of the GNU General Public License version 2 as
110b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * published by the Free Software Foundation.
120b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
130b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * This program is distributed in the hope that it will be useful, but
140b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * WITHOUT ANY WARRANTY; without even the implied warranty of
150b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
160b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * General Public License for more details.
170b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
180b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * You should have received a copy of the GNU General Public License
190b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * along with this program; if not, write to the Free Software
200b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
210b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * 02110-1301 USA
220b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi *
230b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi */
240b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
250b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/module.h>
260b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/types.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
280b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/kernel.h>
290b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/fs.h>
300b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/platform_device.h>
31019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi#include <linux/of.h>
32019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi#include <linux/of_platform.h>
338bea8672edfca7ec5f661cafb218f1205863b343Stephen Rothwell#include <linux/i2c/twl.h>
340b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi#include <linux/mfd/core.h>
3557fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi#include <linux/mfd/twl4030-audio.h>
360b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
374fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi#define TWL4030_AUDIO_CELLS	2
380b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
394fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusistatic struct platform_device *twl4030_audio_dev;
400b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
414fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusistruct twl4030_audio_resource {
420b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	int request_count;
430b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	u8 reg;
440b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	u8 mask;
450b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi};
460b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
474fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusistruct twl4030_audio {
48f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	unsigned int audio_mclk;
490b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	struct mutex mutex;
5057fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	struct twl4030_audio_resource resource[TWL4030_AUDIO_RES_MAX];
514fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct mfd_cell cells[TWL4030_AUDIO_CELLS];
520b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi};
530b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
540b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi/*
550b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * Modify the resource, the function returns the content of the register
560b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * after the modification.
570b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi */
5857fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusistatic int twl4030_audio_set_resource(enum twl4030_audio_res id, int enable)
590b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
604fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
610b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	u8 val;
620b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
638bea8672edfca7ec5f661cafb218f1205863b343Stephen Rothwell	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
644fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi			audio->resource[id].reg);
650b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
660b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	if (enable)
674fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val |= audio->resource[id].mask;
680b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	else
694fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val &= ~audio->resource[id].mask;
700b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
718bea8672edfca7ec5f661cafb218f1205863b343Stephen Rothwell	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
724fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi					val, audio->resource[id].reg);
730b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
740b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return val;
750b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
760b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
7757fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusistatic inline int twl4030_audio_get_resource(enum twl4030_audio_res id)
780b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
794fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
800b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	u8 val;
810b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
828bea8672edfca7ec5f661cafb218f1205863b343Stephen Rothwell	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
834fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi			audio->resource[id].reg);
840b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
850b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return val;
860b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
870b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
880b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi/*
890b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * Enable the resource.
900b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * The function returns with error or the content of the register
910b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi */
9257fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusiint twl4030_audio_enable_resource(enum twl4030_audio_res id)
930b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
944fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
950b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	int val;
960b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
9757fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	if (id >= TWL4030_AUDIO_RES_MAX) {
984fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		dev_err(&twl4030_audio_dev->dev,
990b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi				"Invalid resource ID (%u)\n", id);
1000b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		return -EINVAL;
1010b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
1020b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1034fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	mutex_lock(&audio->mutex);
1044fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	if (!audio->resource[id].request_count)
1050b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		/* Resource was disabled, enable it */
1064fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val = twl4030_audio_set_resource(id, 1);
1070b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	else
1084fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val = twl4030_audio_get_resource(id);
1090b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1104fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	audio->resource[id].request_count++;
1114fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	mutex_unlock(&audio->mutex);
1120b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1130b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return val;
1140b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
11557fe7251f5bfc4332f24479376de48a1e8ca6211Peter UjfalusiEXPORT_SYMBOL_GPL(twl4030_audio_enable_resource);
1160b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1170b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi/*
1180b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * Disable the resource.
1190b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi * The function returns with error or the content of the register
1200b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi */
1216049bcefada077c5d3aec59f093701df711ad235Mark Brownint twl4030_audio_disable_resource(enum twl4030_audio_res id)
1220b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
1234fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
1240b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	int val;
1250b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
12657fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	if (id >= TWL4030_AUDIO_RES_MAX) {
1274fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		dev_err(&twl4030_audio_dev->dev,
1280b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi				"Invalid resource ID (%u)\n", id);
1290b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		return -EINVAL;
1300b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
1310b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1324fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	mutex_lock(&audio->mutex);
1334fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	if (!audio->resource[id].request_count) {
1344fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		dev_err(&twl4030_audio_dev->dev,
1350b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi			"Resource has been disabled already (%u)\n", id);
1364fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		mutex_unlock(&audio->mutex);
1370b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		return -EPERM;
1380b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
1394fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	audio->resource[id].request_count--;
1400b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1414fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	if (!audio->resource[id].request_count)
1420b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		/* Resource can be disabled now */
1434fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val = twl4030_audio_set_resource(id, 0);
1440b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	else
1454fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		val = twl4030_audio_get_resource(id);
1460b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1474fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	mutex_unlock(&audio->mutex);
1480b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
1490b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return val;
1500b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
15157fe7251f5bfc4332f24479376de48a1e8ca6211Peter UjfalusiEXPORT_SYMBOL_GPL(twl4030_audio_disable_resource);
1520b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
15357fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusiunsigned int twl4030_audio_get_mclk(void)
154f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi{
1554fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
156f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi
1574fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	return audio->audio_mclk;
158f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi}
15957fe7251f5bfc4332f24479376de48a1e8ca6211Peter UjfalusiEXPORT_SYMBOL_GPL(twl4030_audio_get_mclk);
160f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi
161019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusistatic bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata,
162019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			      struct device_node *node)
163019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi{
164019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (pdata && pdata->codec)
165019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		return true;
166019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
167019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (of_find_node_by_name(node, "codec"))
168019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		return true;
169019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
170019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	return false;
171019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi}
172019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
173019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusistatic bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata,
174019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			      struct device_node *node)
175019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi{
176019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	int vibra;
177019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
178019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (pdata && pdata->vibra)
179019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		return true;
180019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
181019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (!of_property_read_u32(node, "ti,enable-vibra", &vibra) && vibra)
182019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		return true;
183019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
184019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	return false;
185019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi}
186019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
187f791be492f76dea7b0641ed227a60eeb2fa7e255Bill Pembertonstatic int twl4030_audio_probe(struct platform_device *pdev)
1880b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
1894fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	struct twl4030_audio *audio;
190334a41ce9b753ec615e8c6c50ee07d6197190610Jingoo Han	struct twl4030_audio_data *pdata = dev_get_platdata(&pdev->dev);
191019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	struct device_node *node = pdev->dev.of_node;
1920b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	struct mfd_cell *cell = NULL;
1930b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	int ret, childs = 0;
194f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	u8 val;
195f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi
196019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (!pdata && !node) {
197f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		dev_err(&pdev->dev, "Platform data is missing\n");
198f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		return -EINVAL;
199f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	}
200f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi
201cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio),
202cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi			     GFP_KERNEL);
203cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	if (!audio)
204cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi		return -ENOMEM;
205cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi
206cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	mutex_init(&audio->mutex);
207c531241dcc010e4457e0eb9401aaeae0a56bf5c6Peter Ujfalusi	audio->audio_mclk = twl_get_hfclk_rate();
208cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi
209f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	/* Configure APLL_INFREQ and disable APLL if enabled */
210cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	switch (audio->audio_mclk) {
211f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	case 19200000:
212cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi		val = TWL4030_APLL_INFREQ_19200KHZ;
213f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		break;
214f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	case 26000000:
215cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi		val = TWL4030_APLL_INFREQ_26000KHZ;
216f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		break;
217f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	case 38400000:
218cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi		val = TWL4030_APLL_INFREQ_38400KHZ;
219f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		break;
220f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	default:
221f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		dev_err(&pdev->dev, "Invalid audio_mclk\n");
222f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi		return -EINVAL;
223f9b4639e045c750e2bad37462476403995508350Peter Ujfalusi	}
224cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL);
2250b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2260b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	/* Codec power */
22757fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
22857fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	audio->resource[TWL4030_AUDIO_RES_POWER].mask = TWL4030_CODECPDZ;
2290b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2300b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	/* PLL */
23157fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL;
23257fe7251f5bfc4332f24479376de48a1e8ca6211Peter Ujfalusi	audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN;
2330b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
234019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (twl4030_audio_has_codec(pdata, node)) {
2354fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		cell = &audio->cells[childs];
236f0fba2ad1b6b53d5360125c41953b7afcd6deff0Liam Girdwood		cell->name = "twl4030-codec";
237019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		if (pdata) {
238019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			cell->platform_data = pdata->codec;
239019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			cell->pdata_size = sizeof(*pdata->codec);
240019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		}
2410b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		childs++;
2420b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
243019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	if (twl4030_audio_has_vibra(pdata, node)) {
2444fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		cell = &audio->cells[childs];
245f0fba2ad1b6b53d5360125c41953b7afcd6deff0Liam Girdwood		cell->name = "twl4030-vibra";
246019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		if (pdata) {
247019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			cell->platform_data = pdata->vibra;
248019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi			cell->pdata_size = sizeof(*pdata->vibra);
249019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		}
2500b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		childs++;
2510b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
2520b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
253cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	platform_set_drvdata(pdev, audio);
254cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi	twl4030_audio_dev = pdev;
255cdf4b67099ee8e038178a9e7d83c1aa16618c1caPeter Ujfalusi
2560b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	if (childs)
2574fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi		ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells,
25855692af5eb587f7592d6c2713e1e0eeaab0f6c31Mark Brown				      childs, NULL, 0, NULL);
2590b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	else {
2600b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		dev_err(&pdev->dev, "No platform data found for childs\n");
2610b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		ret = -ENODEV;
2620b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	}
2630b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
26496ac2d1a3a352ce1f4d669ad222677ba2ed76271Jingoo Han	if (ret)
26539c1421db694ee2594bbb2196b1b5a3085e3c656Peter Ujfalusi		twl4030_audio_dev = NULL;
2660b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2670b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return ret;
2680b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
2690b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2704740f73fe5388ab5d22d552d2a0dacc62418a70cBill Pembertonstatic int twl4030_audio_remove(struct platform_device *pdev)
2710b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi{
2720b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	mfd_remove_devices(&pdev->dev);
2734fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusi	twl4030_audio_dev = NULL;
2740b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2750b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	return 0;
2760b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi}
2770b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
278019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusistatic const struct of_device_id twl4030_audio_of_match[] = {
279019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	{.compatible = "ti,twl4030-audio", },
280019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi	{ },
281019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi};
282019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter UjfalusiMODULE_DEVICE_TABLE(of, twl4030_audio_of_match);
283019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi
2844fe5668b73d7ad041101656c98f3a58d86f68840Peter Ujfalusistatic struct platform_driver twl4030_audio_driver = {
2850b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	.driver		= {
2860b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi		.owner	= THIS_MODULE,
287f0fba2ad1b6b53d5360125c41953b7afcd6deff0Liam Girdwood		.name	= "twl4030-audio",
288019a7e6b7b312b17cd74b45d09d4ec17486c4088Peter Ujfalusi		.of_match_table = twl4030_audio_of_match,
2890b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi	},
29041569a16e4e12910e14ce98edea9ef30bd89299bPeter Ujfalusi	.probe		= twl4030_audio_probe,
29184449216b01f9c2b4c9b1882f9d6abba07b7b7caBill Pemberton	.remove		= twl4030_audio_remove,
2920b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi};
2930b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
29465349d60d27e850c94544567c91ab1be3e4c0777Mark Brownmodule_platform_driver(twl4030_audio_driver);
2950b83ddebc6e884dc0221358cf68c461520fbdd8ePeter Ujfalusi
2964a7c00cd94d4ca7061c481fe823a256e37436044Peter UjfalusiMODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
29741569a16e4e12910e14ce98edea9ef30bd89299bPeter UjfalusiMODULE_DESCRIPTION("TWL4030 audio block MFD driver");
2980b83ddebc6e884dc0221358cf68c461520fbdd8ePeter UjfalusiMODULE_LICENSE("GPL");
29941569a16e4e12910e14ce98edea9ef30bd89299bPeter UjfalusiMODULE_ALIAS("platform:twl4030-audio");
300