[go: nahoru, domu]

wl1273-core.c revision 383268a8e282fb549dabe3a33ccafc9434ab6006
1383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen/*
2383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * MFD driver for wl1273 FM radio and audio codec submodules.
3383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen *
4383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * Copyright (C) 2010 Nokia Corporation
5383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
6383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen *
7383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * This program is free software; you can redistribute it and/or modify
8383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * it under the terms of the GNU General Public License version 2 as
9383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * published by the Free Software Foundation.
10383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen *
11383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * This program is distributed in the hope that it will be useful, but
12383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * WITHOUT ANY WARRANTY; without even the implied warranty of
13383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * General Public License for more details.
15383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen *
16383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * You should have received a copy of the GNU General Public License
17383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * along with this program; if not, write to the Free Software
18383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen * 02110-1301 USA
20383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen *
21383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen */
22383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
23383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen#include <linux/mfd/wl1273-core.h>
24383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen#include <linux/slab.h>
25383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
26383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen#define DRIVER_DESC "WL1273 FM Radio Core"
27383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
28383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic struct i2c_device_id wl1273_driver_id_table[] = {
29383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	{ WL1273_FM_DRIVER_NAME, 0 },
30383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	{ }
31383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen};
32383268a8e282fb549dabe3a33ccafc9434ab6006Matti AaltonenMODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
33383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
34383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic int wl1273_core_remove(struct i2c_client *client)
35383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen{
36383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	struct wl1273_core *core = i2c_get_clientdata(client);
37383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
38383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	dev_dbg(&client->dev, "%s\n", __func__);
39383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
40383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	mfd_remove_devices(&client->dev);
41383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	i2c_set_clientdata(client, NULL);
42383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	kfree(core);
43383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
44383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	return 0;
45383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen}
46383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
47383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic int __devinit wl1273_core_probe(struct i2c_client *client,
48383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen				       const struct i2c_device_id *id)
49383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen{
50383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	struct wl1273_fm_platform_data *pdata = client->dev.platform_data;
51383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	struct wl1273_core *core;
52383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	struct mfd_cell *cell;
53383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	int children = 0;
54383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	int r = 0;
55383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
56383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	dev_dbg(&client->dev, "%s\n", __func__);
57383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
58383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (!pdata) {
59383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		dev_err(&client->dev, "No platform data.\n");
60383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		return -EINVAL;
61383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	}
62383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
63383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (!(pdata->children & WL1273_RADIO_CHILD)) {
64383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		dev_err(&client->dev, "Cannot function without radio child.\n");
65383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		return -EINVAL;
66383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	}
67383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
68383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	core = kzalloc(sizeof(*core), GFP_KERNEL);
69383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (!core)
70383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		return -ENOMEM;
71383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
72383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	core->pdata = pdata;
73383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	core->client = client;
74383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	mutex_init(&core->lock);
75383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
76383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	i2c_set_clientdata(client, core);
77383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
78383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	dev_dbg(&client->dev, "%s: Have V4L2.\n", __func__);
79383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
80383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	cell = &core->cells[children];
81383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	cell->name = "wl1273_fm_radio";
82383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	cell->platform_data = &core;
83383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	cell->data_size = sizeof(core);
84383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	children++;
85383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
86383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (pdata->children & WL1273_CODEC_CHILD) {
87383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		cell = &core->cells[children];
88383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
89383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
90383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		cell->name = "wl1273-codec";
91383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		cell->platform_data = &core;
92383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		cell->data_size = sizeof(core);
93383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		children++;
94383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	}
95383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
96383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	dev_dbg(&client->dev, "%s: number of children: %d.\n",
97383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		__func__, children);
98383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
99383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	r = mfd_add_devices(&client->dev, -1, core->cells,
100383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen			    children, NULL, 0);
101383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (r)
102383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		goto err;
103383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
104383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	return 0;
105383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
106383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenerr:
107383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	i2c_set_clientdata(client, NULL);
108383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	pdata->free_resources();
109383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	kfree(core);
110383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
111383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	dev_dbg(&client->dev, "%s\n", __func__);
112383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
113383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	return r;
114383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen}
115383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
116383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic struct i2c_driver wl1273_core_driver = {
117383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	.driver = {
118383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		.name = WL1273_FM_DRIVER_NAME,
119383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	},
120383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	.probe = wl1273_core_probe,
121383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	.id_table = wl1273_driver_id_table,
122383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	.remove = __devexit_p(wl1273_core_remove),
123383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen};
124383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
125383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic int __init wl1273_core_init(void)
126383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen{
127383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	int r;
128383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
129383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	r = i2c_add_driver(&wl1273_core_driver);
130383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	if (r) {
131383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		pr_err(WL1273_FM_DRIVER_NAME
132383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		       ": driver registration failed\n");
133383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen		return r;
134383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	}
135383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
136383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	return r;
137383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen}
138383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
139383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenstatic void __exit wl1273_core_exit(void)
140383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen{
141383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen	i2c_del_driver(&wl1273_core_driver);
142383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen}
143383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenlate_initcall(wl1273_core_init);
144383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonenmodule_exit(wl1273_core_exit);
145383268a8e282fb549dabe3a33ccafc9434ab6006Matti Aaltonen
146383268a8e282fb549dabe3a33ccafc9434ab6006Matti AaltonenMODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
147383268a8e282fb549dabe3a33ccafc9434ab6006Matti AaltonenMODULE_DESCRIPTION(DRIVER_DESC);
148383268a8e282fb549dabe3a33ccafc9434ab6006Matti AaltonenMODULE_LICENSE("GPL");
149