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