xref: /OK3568_Linux_fs/kernel/drivers/mfd/si476x-i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD
4*4882a593Smuzhiyun  * device
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2012 Innovative Converged Devices(ICD)
7*4882a593Smuzhiyun  * Copyright (C) 2013 Andrey Smirnov
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/gpio.h>
17*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
18*4882a593Smuzhiyun #include <linux/i2c.h>
19*4882a593Smuzhiyun #include <linux/err.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <linux/mfd/si476x-core.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define SI476X_MAX_IO_ERRORS		10
24*4882a593Smuzhiyun #define SI476X_DRIVER_RDS_FIFO_DEPTH	128
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /**
27*4882a593Smuzhiyun  * si476x_core_config_pinmux() - pin function configuration function
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * @core: Core device structure
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * Configure the functions of the pins of the radio chip.
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * The function returns zero in case of succes or negative error code
34*4882a593Smuzhiyun  * otherwise.
35*4882a593Smuzhiyun  */
si476x_core_config_pinmux(struct si476x_core * core)36*4882a593Smuzhiyun static int si476x_core_config_pinmux(struct si476x_core *core)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	int err;
39*4882a593Smuzhiyun 	dev_dbg(&core->client->dev, "Configuring pinmux\n");
40*4882a593Smuzhiyun 	err = si476x_core_cmd_dig_audio_pin_cfg(core,
41*4882a593Smuzhiyun 						core->pinmux.dclk,
42*4882a593Smuzhiyun 						core->pinmux.dfs,
43*4882a593Smuzhiyun 						core->pinmux.dout,
44*4882a593Smuzhiyun 						core->pinmux.xout);
45*4882a593Smuzhiyun 	if (err < 0) {
46*4882a593Smuzhiyun 		dev_err(&core->client->dev,
47*4882a593Smuzhiyun 			"Failed to configure digital audio pins(err = %d)\n",
48*4882a593Smuzhiyun 			err);
49*4882a593Smuzhiyun 		return err;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	err = si476x_core_cmd_zif_pin_cfg(core,
53*4882a593Smuzhiyun 					  core->pinmux.iqclk,
54*4882a593Smuzhiyun 					  core->pinmux.iqfs,
55*4882a593Smuzhiyun 					  core->pinmux.iout,
56*4882a593Smuzhiyun 					  core->pinmux.qout);
57*4882a593Smuzhiyun 	if (err < 0) {
58*4882a593Smuzhiyun 		dev_err(&core->client->dev,
59*4882a593Smuzhiyun 			"Failed to configure ZIF pins(err = %d)\n",
60*4882a593Smuzhiyun 			err);
61*4882a593Smuzhiyun 		return err;
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core,
65*4882a593Smuzhiyun 						      core->pinmux.icin,
66*4882a593Smuzhiyun 						      core->pinmux.icip,
67*4882a593Smuzhiyun 						      core->pinmux.icon,
68*4882a593Smuzhiyun 						      core->pinmux.icop);
69*4882a593Smuzhiyun 	if (err < 0) {
70*4882a593Smuzhiyun 		dev_err(&core->client->dev,
71*4882a593Smuzhiyun 			"Failed to configure IC-Link/GPO pins(err = %d)\n",
72*4882a593Smuzhiyun 			err);
73*4882a593Smuzhiyun 		return err;
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	err = si476x_core_cmd_ana_audio_pin_cfg(core,
77*4882a593Smuzhiyun 						core->pinmux.lrout);
78*4882a593Smuzhiyun 	if (err < 0) {
79*4882a593Smuzhiyun 		dev_err(&core->client->dev,
80*4882a593Smuzhiyun 			"Failed to configure analog audio pins(err = %d)\n",
81*4882a593Smuzhiyun 			err);
82*4882a593Smuzhiyun 		return err;
83*4882a593Smuzhiyun 	}
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	err = si476x_core_cmd_intb_pin_cfg(core,
86*4882a593Smuzhiyun 					   core->pinmux.intb,
87*4882a593Smuzhiyun 					   core->pinmux.a1);
88*4882a593Smuzhiyun 	if (err < 0) {
89*4882a593Smuzhiyun 		dev_err(&core->client->dev,
90*4882a593Smuzhiyun 			"Failed to configure interrupt pins(err = %d)\n",
91*4882a593Smuzhiyun 			err);
92*4882a593Smuzhiyun 		return err;
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
si476x_core_schedule_polling_work(struct si476x_core * core)98*4882a593Smuzhiyun static inline void si476x_core_schedule_polling_work(struct si476x_core *core)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	schedule_delayed_work(&core->status_monitor,
101*4882a593Smuzhiyun 			      usecs_to_jiffies(SI476X_STATUS_POLL_US));
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /**
105*4882a593Smuzhiyun  * si476x_core_start() - early chip startup function
106*4882a593Smuzhiyun  * @core: Core device structure
107*4882a593Smuzhiyun  * @soft: When set, this flag forces "soft" startup, where "soft"
108*4882a593Smuzhiyun  * power down is the one done by sending appropriate command instead
109*4882a593Smuzhiyun  * of using reset pin of the tuner
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * Perform required startup sequence to correctly power
112*4882a593Smuzhiyun  * up the chip and perform initial configuration. It does the
113*4882a593Smuzhiyun  * following sequence of actions:
114*4882a593Smuzhiyun  *       1. Claims and enables the power supplies VD and VIO1 required
115*4882a593Smuzhiyun  *          for I2C interface of the chip operation.
116*4882a593Smuzhiyun  *       2. Waits for 100us, pulls the reset line up, enables irq,
117*4882a593Smuzhiyun  *          waits for another 100us as it is specified by the
118*4882a593Smuzhiyun  *          datasheet.
119*4882a593Smuzhiyun  *       3. Sends 'POWER_UP' command to the device with all provided
120*4882a593Smuzhiyun  *          information about power-up parameters.
121*4882a593Smuzhiyun  *       4. Configures, pin multiplexor, disables digital audio and
122*4882a593Smuzhiyun  *          configures interrupt sources.
123*4882a593Smuzhiyun  *
124*4882a593Smuzhiyun  * The function returns zero in case of succes or negative error code
125*4882a593Smuzhiyun  * otherwise.
126*4882a593Smuzhiyun  */
si476x_core_start(struct si476x_core * core,bool soft)127*4882a593Smuzhiyun int si476x_core_start(struct si476x_core *core, bool soft)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	struct i2c_client *client = core->client;
130*4882a593Smuzhiyun 	int err;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (!soft) {
133*4882a593Smuzhiyun 		if (gpio_is_valid(core->gpio_reset))
134*4882a593Smuzhiyun 			gpio_set_value_cansleep(core->gpio_reset, 1);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		if (client->irq)
137*4882a593Smuzhiyun 			enable_irq(client->irq);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		udelay(100);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 		if (!client->irq) {
142*4882a593Smuzhiyun 			atomic_set(&core->is_alive, 1);
143*4882a593Smuzhiyun 			si476x_core_schedule_polling_work(core);
144*4882a593Smuzhiyun 		}
145*4882a593Smuzhiyun 	} else {
146*4882a593Smuzhiyun 		if (client->irq)
147*4882a593Smuzhiyun 			enable_irq(client->irq);
148*4882a593Smuzhiyun 		else {
149*4882a593Smuzhiyun 			atomic_set(&core->is_alive, 1);
150*4882a593Smuzhiyun 			si476x_core_schedule_polling_work(core);
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	err = si476x_core_cmd_power_up(core,
155*4882a593Smuzhiyun 				       &core->power_up_parameters);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (err < 0) {
158*4882a593Smuzhiyun 		dev_err(&core->client->dev,
159*4882a593Smuzhiyun 			"Power up failure(err = %d)\n",
160*4882a593Smuzhiyun 			err);
161*4882a593Smuzhiyun 		goto disable_irq;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (client->irq)
165*4882a593Smuzhiyun 		atomic_set(&core->is_alive, 1);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	err = si476x_core_config_pinmux(core);
168*4882a593Smuzhiyun 	if (err < 0) {
169*4882a593Smuzhiyun 		dev_err(&core->client->dev,
170*4882a593Smuzhiyun 			"Failed to configure pinmux(err = %d)\n",
171*4882a593Smuzhiyun 			err);
172*4882a593Smuzhiyun 		goto disable_irq;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (client->irq) {
176*4882a593Smuzhiyun 		err = regmap_write(core->regmap,
177*4882a593Smuzhiyun 				   SI476X_PROP_INT_CTL_ENABLE,
178*4882a593Smuzhiyun 				   SI476X_RDSIEN |
179*4882a593Smuzhiyun 				   SI476X_STCIEN |
180*4882a593Smuzhiyun 				   SI476X_CTSIEN);
181*4882a593Smuzhiyun 		if (err < 0) {
182*4882a593Smuzhiyun 			dev_err(&core->client->dev,
183*4882a593Smuzhiyun 				"Failed to configure interrupt sources"
184*4882a593Smuzhiyun 				"(err = %d)\n", err);
185*4882a593Smuzhiyun 			goto disable_irq;
186*4882a593Smuzhiyun 		}
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun disable_irq:
192*4882a593Smuzhiyun 	if (err == -ENODEV)
193*4882a593Smuzhiyun 		atomic_set(&core->is_alive, 0);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (client->irq)
196*4882a593Smuzhiyun 		disable_irq(client->irq);
197*4882a593Smuzhiyun 	else
198*4882a593Smuzhiyun 		cancel_delayed_work_sync(&core->status_monitor);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (gpio_is_valid(core->gpio_reset))
201*4882a593Smuzhiyun 		gpio_set_value_cansleep(core->gpio_reset, 0);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return err;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_start);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun  * si476x_core_stop() - chip power-down function
209*4882a593Smuzhiyun  * @core: Core device structure
210*4882a593Smuzhiyun  * @soft: When set, function sends a POWER_DOWN command instead of
211*4882a593Smuzhiyun  * bringing reset line low
212*4882a593Smuzhiyun  *
213*4882a593Smuzhiyun  * Power down the chip by performing following actions:
214*4882a593Smuzhiyun  * 1. Disable IRQ or stop the polling worker
215*4882a593Smuzhiyun  * 2. Send the POWER_DOWN command if the power down is soft or bring
216*4882a593Smuzhiyun  *    reset line low if not.
217*4882a593Smuzhiyun  *
218*4882a593Smuzhiyun  * The function returns zero in case of succes or negative error code
219*4882a593Smuzhiyun  * otherwise.
220*4882a593Smuzhiyun  */
si476x_core_stop(struct si476x_core * core,bool soft)221*4882a593Smuzhiyun int si476x_core_stop(struct si476x_core *core, bool soft)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int err = 0;
224*4882a593Smuzhiyun 	atomic_set(&core->is_alive, 0);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (soft) {
227*4882a593Smuzhiyun 		/* TODO: This probably shoud be a configurable option,
228*4882a593Smuzhiyun 		 * so it is possible to have the chips keep their
229*4882a593Smuzhiyun 		 * oscillators running
230*4882a593Smuzhiyun 		 */
231*4882a593Smuzhiyun 		struct si476x_power_down_args args = {
232*4882a593Smuzhiyun 			.xosc = false,
233*4882a593Smuzhiyun 		};
234*4882a593Smuzhiyun 		err = si476x_core_cmd_power_down(core, &args);
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* We couldn't disable those before
238*4882a593Smuzhiyun 	 * 'si476x_core_cmd_power_down' since we expect to get CTS
239*4882a593Smuzhiyun 	 * interrupt */
240*4882a593Smuzhiyun 	if (core->client->irq)
241*4882a593Smuzhiyun 		disable_irq(core->client->irq);
242*4882a593Smuzhiyun 	else
243*4882a593Smuzhiyun 		cancel_delayed_work_sync(&core->status_monitor);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (!soft) {
246*4882a593Smuzhiyun 		if (gpio_is_valid(core->gpio_reset))
247*4882a593Smuzhiyun 			gpio_set_value_cansleep(core->gpio_reset, 0);
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 	return err;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_stop);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun /**
254*4882a593Smuzhiyun  * si476x_core_set_power_state() - set the level at which the power is
255*4882a593Smuzhiyun  * supplied for the chip.
256*4882a593Smuzhiyun  * @core: Core device structure
257*4882a593Smuzhiyun  * @next_state: enum si476x_power_state describing power state to
258*4882a593Smuzhiyun  *              switch to.
259*4882a593Smuzhiyun  *
260*4882a593Smuzhiyun  * Switch on all the required power supplies
261*4882a593Smuzhiyun  *
262*4882a593Smuzhiyun  * This function returns 0 in case of suvccess and negative error code
263*4882a593Smuzhiyun  * otherwise.
264*4882a593Smuzhiyun  */
si476x_core_set_power_state(struct si476x_core * core,enum si476x_power_state next_state)265*4882a593Smuzhiyun int si476x_core_set_power_state(struct si476x_core *core,
266*4882a593Smuzhiyun 				enum si476x_power_state next_state)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	/*
269*4882a593Smuzhiyun 	   It is not clear form the datasheet if it is possible to
270*4882a593Smuzhiyun 	   work with device if not all power domains are operational.
271*4882a593Smuzhiyun 	   So for now the power-up policy is "power-up all the things!"
272*4882a593Smuzhiyun 	 */
273*4882a593Smuzhiyun 	int err = 0;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	if (core->power_state == SI476X_POWER_INCONSISTENT) {
276*4882a593Smuzhiyun 		dev_err(&core->client->dev,
277*4882a593Smuzhiyun 			"The device in inconsistent power state\n");
278*4882a593Smuzhiyun 		return -EINVAL;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (next_state != core->power_state) {
282*4882a593Smuzhiyun 		switch (next_state) {
283*4882a593Smuzhiyun 		case SI476X_POWER_UP_FULL:
284*4882a593Smuzhiyun 			err = regulator_bulk_enable(ARRAY_SIZE(core->supplies),
285*4882a593Smuzhiyun 						    core->supplies);
286*4882a593Smuzhiyun 			if (err < 0) {
287*4882a593Smuzhiyun 				core->power_state = SI476X_POWER_INCONSISTENT;
288*4882a593Smuzhiyun 				break;
289*4882a593Smuzhiyun 			}
290*4882a593Smuzhiyun 			/*
291*4882a593Smuzhiyun 			 * Startup timing diagram recommends to have a
292*4882a593Smuzhiyun 			 * 100 us delay between enabling of the power
293*4882a593Smuzhiyun 			 * supplies and turning the tuner on.
294*4882a593Smuzhiyun 			 */
295*4882a593Smuzhiyun 			udelay(100);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 			err = si476x_core_start(core, false);
298*4882a593Smuzhiyun 			if (err < 0)
299*4882a593Smuzhiyun 				goto disable_regulators;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 			core->power_state = next_state;
302*4882a593Smuzhiyun 			break;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		case SI476X_POWER_DOWN:
305*4882a593Smuzhiyun 			core->power_state = next_state;
306*4882a593Smuzhiyun 			err = si476x_core_stop(core, false);
307*4882a593Smuzhiyun 			if (err < 0)
308*4882a593Smuzhiyun 				core->power_state = SI476X_POWER_INCONSISTENT;
309*4882a593Smuzhiyun disable_regulators:
310*4882a593Smuzhiyun 			err = regulator_bulk_disable(ARRAY_SIZE(core->supplies),
311*4882a593Smuzhiyun 						     core->supplies);
312*4882a593Smuzhiyun 			if (err < 0)
313*4882a593Smuzhiyun 				core->power_state = SI476X_POWER_INCONSISTENT;
314*4882a593Smuzhiyun 			break;
315*4882a593Smuzhiyun 		default:
316*4882a593Smuzhiyun 			BUG();
317*4882a593Smuzhiyun 		}
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return err;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_set_power_state);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun /**
325*4882a593Smuzhiyun  * si476x_core_report_drainer_stop() - mark the completion of the RDS
326*4882a593Smuzhiyun  * buffer drain porcess by the worker.
327*4882a593Smuzhiyun  *
328*4882a593Smuzhiyun  * @core: Core device structure
329*4882a593Smuzhiyun  */
si476x_core_report_drainer_stop(struct si476x_core * core)330*4882a593Smuzhiyun static inline void si476x_core_report_drainer_stop(struct si476x_core *core)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	mutex_lock(&core->rds_drainer_status_lock);
333*4882a593Smuzhiyun 	core->rds_drainer_is_working = false;
334*4882a593Smuzhiyun 	mutex_unlock(&core->rds_drainer_status_lock);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun /**
338*4882a593Smuzhiyun  * si476x_core_start_rds_drainer_once() - start RDS drainer worker if
339*4882a593Smuzhiyun  * ther is none working, do nothing otherwise
340*4882a593Smuzhiyun  *
341*4882a593Smuzhiyun  * @core: Datastructure corresponding to the chip.
342*4882a593Smuzhiyun  */
si476x_core_start_rds_drainer_once(struct si476x_core * core)343*4882a593Smuzhiyun static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	mutex_lock(&core->rds_drainer_status_lock);
346*4882a593Smuzhiyun 	if (!core->rds_drainer_is_working) {
347*4882a593Smuzhiyun 		core->rds_drainer_is_working = true;
348*4882a593Smuzhiyun 		schedule_work(&core->rds_fifo_drainer);
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 	mutex_unlock(&core->rds_drainer_status_lock);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun /**
353*4882a593Smuzhiyun  * si476x_drain_rds_fifo() - RDS buffer drainer.
354*4882a593Smuzhiyun  * @work: struct work_struct being ppassed to the function by the
355*4882a593Smuzhiyun  * kernel.
356*4882a593Smuzhiyun  *
357*4882a593Smuzhiyun  * Drain the contents of the RDS FIFO of
358*4882a593Smuzhiyun  */
si476x_core_drain_rds_fifo(struct work_struct * work)359*4882a593Smuzhiyun static void si476x_core_drain_rds_fifo(struct work_struct *work)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	int err;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	struct si476x_core *core = container_of(work, struct si476x_core,
364*4882a593Smuzhiyun 						rds_fifo_drainer);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	struct si476x_rds_status_report report;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	si476x_core_lock(core);
369*4882a593Smuzhiyun 	err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report);
370*4882a593Smuzhiyun 	if (!err) {
371*4882a593Smuzhiyun 		int i = report.rdsfifoused;
372*4882a593Smuzhiyun 		dev_dbg(&core->client->dev,
373*4882a593Smuzhiyun 			"%d elements in RDS FIFO. Draining.\n", i);
374*4882a593Smuzhiyun 		for (; i > 0; --i) {
375*4882a593Smuzhiyun 			err = si476x_core_cmd_fm_rds_status(core, false, false,
376*4882a593Smuzhiyun 							    (i == 1), &report);
377*4882a593Smuzhiyun 			if (err < 0)
378*4882a593Smuzhiyun 				goto unlock;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 			kfifo_in(&core->rds_fifo, report.rds,
381*4882a593Smuzhiyun 				 sizeof(report.rds));
382*4882a593Smuzhiyun 			dev_dbg(&core->client->dev, "RDS data:\n %*ph\n",
383*4882a593Smuzhiyun 				(int)sizeof(report.rds), report.rds);
384*4882a593Smuzhiyun 		}
385*4882a593Smuzhiyun 		dev_dbg(&core->client->dev, "Drrrrained!\n");
386*4882a593Smuzhiyun 		wake_up_interruptible(&core->rds_read_queue);
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun unlock:
390*4882a593Smuzhiyun 	si476x_core_unlock(core);
391*4882a593Smuzhiyun 	si476x_core_report_drainer_stop(core);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /**
395*4882a593Smuzhiyun  * si476x_core_pronounce_dead()
396*4882a593Smuzhiyun  *
397*4882a593Smuzhiyun  * @core: Core device structure
398*4882a593Smuzhiyun  *
399*4882a593Smuzhiyun  * Mark the device as being dead and wake up all potentially waiting
400*4882a593Smuzhiyun  * threads of execution.
401*4882a593Smuzhiyun  *
402*4882a593Smuzhiyun  */
si476x_core_pronounce_dead(struct si476x_core * core)403*4882a593Smuzhiyun static void si476x_core_pronounce_dead(struct si476x_core *core)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	dev_info(&core->client->dev, "Core device is dead.\n");
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	atomic_set(&core->is_alive, 0);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* Wake up al possible waiting processes */
410*4882a593Smuzhiyun 	wake_up_interruptible(&core->rds_read_queue);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	atomic_set(&core->cts, 1);
413*4882a593Smuzhiyun 	wake_up(&core->command);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	atomic_set(&core->stc, 1);
416*4882a593Smuzhiyun 	wake_up(&core->tuning);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun /**
420*4882a593Smuzhiyun  * si476x_core_i2c_xfer()
421*4882a593Smuzhiyun  *
422*4882a593Smuzhiyun  * @core: Core device structure
423*4882a593Smuzhiyun  * @type: Transfer type
424*4882a593Smuzhiyun  * @buf: Transfer buffer for/with data
425*4882a593Smuzhiyun  * @count: Transfer buffer size
426*4882a593Smuzhiyun  *
427*4882a593Smuzhiyun  * Perfrom and I2C transfer(either read or write) and keep a counter
428*4882a593Smuzhiyun  * of I/O errors. If the error counter rises above the threshold
429*4882a593Smuzhiyun  * pronounce device dead.
430*4882a593Smuzhiyun  *
431*4882a593Smuzhiyun  * The function returns zero on succes or negative error code on
432*4882a593Smuzhiyun  * failure.
433*4882a593Smuzhiyun  */
si476x_core_i2c_xfer(struct si476x_core * core,enum si476x_i2c_type type,char * buf,int count)434*4882a593Smuzhiyun int si476x_core_i2c_xfer(struct si476x_core *core,
435*4882a593Smuzhiyun 		    enum si476x_i2c_type type,
436*4882a593Smuzhiyun 		    char *buf, int count)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	static int io_errors_count;
439*4882a593Smuzhiyun 	int err;
440*4882a593Smuzhiyun 	if (type == SI476X_I2C_SEND)
441*4882a593Smuzhiyun 		err = i2c_master_send(core->client, buf, count);
442*4882a593Smuzhiyun 	else
443*4882a593Smuzhiyun 		err = i2c_master_recv(core->client, buf, count);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (err < 0) {
446*4882a593Smuzhiyun 		if (io_errors_count++ > SI476X_MAX_IO_ERRORS)
447*4882a593Smuzhiyun 			si476x_core_pronounce_dead(core);
448*4882a593Smuzhiyun 	} else {
449*4882a593Smuzhiyun 		io_errors_count = 0;
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	return err;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun /**
457*4882a593Smuzhiyun  * si476x_get_status()
458*4882a593Smuzhiyun  * @core: Core device structure
459*4882a593Smuzhiyun  *
460*4882a593Smuzhiyun  * Get the status byte of the core device by berforming one byte I2C
461*4882a593Smuzhiyun  * read.
462*4882a593Smuzhiyun  *
463*4882a593Smuzhiyun  * The function returns a status value or a negative error code on
464*4882a593Smuzhiyun  * error.
465*4882a593Smuzhiyun  */
si476x_core_get_status(struct si476x_core * core)466*4882a593Smuzhiyun static int si476x_core_get_status(struct si476x_core *core)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	u8 response;
469*4882a593Smuzhiyun 	int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV,
470*4882a593Smuzhiyun 				  &response, sizeof(response));
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return (err < 0) ? err : response;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /**
476*4882a593Smuzhiyun  * si476x_get_and_signal_status() - IRQ dispatcher
477*4882a593Smuzhiyun  * @core: Core device structure
478*4882a593Smuzhiyun  *
479*4882a593Smuzhiyun  * Dispatch the arrived interrupt request based on the value of the
480*4882a593Smuzhiyun  * status byte reported by the tuner.
481*4882a593Smuzhiyun  *
482*4882a593Smuzhiyun  */
si476x_core_get_and_signal_status(struct si476x_core * core)483*4882a593Smuzhiyun static void si476x_core_get_and_signal_status(struct si476x_core *core)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	int status = si476x_core_get_status(core);
486*4882a593Smuzhiyun 	if (status < 0) {
487*4882a593Smuzhiyun 		dev_err(&core->client->dev, "Failed to get status\n");
488*4882a593Smuzhiyun 		return;
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	if (status & SI476X_CTS) {
492*4882a593Smuzhiyun 		/* Unfortunately completions could not be used for
493*4882a593Smuzhiyun 		 * signalling CTS since this flag cannot be cleared
494*4882a593Smuzhiyun 		 * in status byte, and therefore once it becomes true
495*4882a593Smuzhiyun 		 * multiple calls to 'complete' would cause the
496*4882a593Smuzhiyun 		 * commands following the current one to be completed
497*4882a593Smuzhiyun 		 * before they actually are */
498*4882a593Smuzhiyun 		dev_dbg(&core->client->dev, "[interrupt] CTSINT\n");
499*4882a593Smuzhiyun 		atomic_set(&core->cts, 1);
500*4882a593Smuzhiyun 		wake_up(&core->command);
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (status & SI476X_FM_RDS_INT) {
504*4882a593Smuzhiyun 		dev_dbg(&core->client->dev, "[interrupt] RDSINT\n");
505*4882a593Smuzhiyun 		si476x_core_start_rds_drainer_once(core);
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	if (status & SI476X_STC_INT) {
509*4882a593Smuzhiyun 		dev_dbg(&core->client->dev, "[interrupt] STCINT\n");
510*4882a593Smuzhiyun 		atomic_set(&core->stc, 1);
511*4882a593Smuzhiyun 		wake_up(&core->tuning);
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
si476x_core_poll_loop(struct work_struct * work)515*4882a593Smuzhiyun static void si476x_core_poll_loop(struct work_struct *work)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	struct si476x_core *core = SI476X_WORK_TO_CORE(work);
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	si476x_core_get_and_signal_status(core);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (atomic_read(&core->is_alive))
522*4882a593Smuzhiyun 		si476x_core_schedule_polling_work(core);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
si476x_core_interrupt(int irq,void * dev)525*4882a593Smuzhiyun static irqreturn_t si476x_core_interrupt(int irq, void *dev)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	struct si476x_core *core = dev;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	si476x_core_get_and_signal_status(core);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	return IRQ_HANDLED;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun /**
535*4882a593Smuzhiyun  * si476x_firmware_version_to_revision()
536*4882a593Smuzhiyun  * @core: Core device structure
537*4882a593Smuzhiyun  * @func: Selects the boot function of the device:
538*4882a593Smuzhiyun  *         *_BOOTLOADER  - Boot loader
539*4882a593Smuzhiyun  *         *_FM_RECEIVER - FM receiver
540*4882a593Smuzhiyun  *         *_AM_RECEIVER - AM receiver
541*4882a593Smuzhiyun  *         *_WB_RECEIVER - Weatherband receiver
542*4882a593Smuzhiyun  * @major:  Firmware major number
543*4882a593Smuzhiyun  * @minor1: Firmware first minor number
544*4882a593Smuzhiyun  * @minor2: Firmware second minor number
545*4882a593Smuzhiyun  *
546*4882a593Smuzhiyun  * Convert a chip's firmware version number into an offset that later
547*4882a593Smuzhiyun  * will be used to as offset in "vtable" of tuner functions
548*4882a593Smuzhiyun  *
549*4882a593Smuzhiyun  * This function returns a positive offset in case of success and a -1
550*4882a593Smuzhiyun  * in case of failure.
551*4882a593Smuzhiyun  */
si476x_core_fwver_to_revision(struct si476x_core * core,int func,int major,int minor1,int minor2)552*4882a593Smuzhiyun static int si476x_core_fwver_to_revision(struct si476x_core *core,
553*4882a593Smuzhiyun 					 int func, int major,
554*4882a593Smuzhiyun 					 int minor1, int minor2)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	switch (func) {
557*4882a593Smuzhiyun 	case SI476X_FUNC_FM_RECEIVER:
558*4882a593Smuzhiyun 		switch (major) {
559*4882a593Smuzhiyun 		case 5:
560*4882a593Smuzhiyun 			return SI476X_REVISION_A10;
561*4882a593Smuzhiyun 		case 8:
562*4882a593Smuzhiyun 			return SI476X_REVISION_A20;
563*4882a593Smuzhiyun 		case 10:
564*4882a593Smuzhiyun 			return SI476X_REVISION_A30;
565*4882a593Smuzhiyun 		default:
566*4882a593Smuzhiyun 			goto unknown_revision;
567*4882a593Smuzhiyun 		}
568*4882a593Smuzhiyun 	case SI476X_FUNC_AM_RECEIVER:
569*4882a593Smuzhiyun 		switch (major) {
570*4882a593Smuzhiyun 		case 5:
571*4882a593Smuzhiyun 			return SI476X_REVISION_A10;
572*4882a593Smuzhiyun 		case 7:
573*4882a593Smuzhiyun 			return SI476X_REVISION_A20;
574*4882a593Smuzhiyun 		case 9:
575*4882a593Smuzhiyun 			return SI476X_REVISION_A30;
576*4882a593Smuzhiyun 		default:
577*4882a593Smuzhiyun 			goto unknown_revision;
578*4882a593Smuzhiyun 		}
579*4882a593Smuzhiyun 	case SI476X_FUNC_WB_RECEIVER:
580*4882a593Smuzhiyun 		switch (major) {
581*4882a593Smuzhiyun 		case 3:
582*4882a593Smuzhiyun 			return SI476X_REVISION_A10;
583*4882a593Smuzhiyun 		case 5:
584*4882a593Smuzhiyun 			return SI476X_REVISION_A20;
585*4882a593Smuzhiyun 		case 7:
586*4882a593Smuzhiyun 			return SI476X_REVISION_A30;
587*4882a593Smuzhiyun 		default:
588*4882a593Smuzhiyun 			goto unknown_revision;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 	case SI476X_FUNC_BOOTLOADER:
591*4882a593Smuzhiyun 	default:		/* FALLTHROUGH */
592*4882a593Smuzhiyun 		BUG();
593*4882a593Smuzhiyun 		return -1;
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun unknown_revision:
597*4882a593Smuzhiyun 	dev_err(&core->client->dev,
598*4882a593Smuzhiyun 		"Unsupported version of the firmware: %d.%d.%d, "
599*4882a593Smuzhiyun 		"reverting to A10 compatible functions\n",
600*4882a593Smuzhiyun 		major, minor1, minor2);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	return SI476X_REVISION_A10;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun /**
606*4882a593Smuzhiyun  * si476x_get_revision_info()
607*4882a593Smuzhiyun  * @core: Core device structure
608*4882a593Smuzhiyun  *
609*4882a593Smuzhiyun  * Get the firmware version number of the device. It is done in
610*4882a593Smuzhiyun  * following three steps:
611*4882a593Smuzhiyun  *    1. Power-up the device
612*4882a593Smuzhiyun  *    2. Send the 'FUNC_INFO' command
613*4882a593Smuzhiyun  *    3. Powering the device down.
614*4882a593Smuzhiyun  *
615*4882a593Smuzhiyun  * The function return zero on success and a negative error code on
616*4882a593Smuzhiyun  * failure.
617*4882a593Smuzhiyun  */
si476x_core_get_revision_info(struct si476x_core * core)618*4882a593Smuzhiyun static int si476x_core_get_revision_info(struct si476x_core *core)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun 	int rval;
621*4882a593Smuzhiyun 	struct si476x_func_info info;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	si476x_core_lock(core);
624*4882a593Smuzhiyun 	rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL);
625*4882a593Smuzhiyun 	if (rval < 0)
626*4882a593Smuzhiyun 		goto exit;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	rval = si476x_core_cmd_func_info(core, &info);
629*4882a593Smuzhiyun 	if (rval < 0)
630*4882a593Smuzhiyun 		goto power_down;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	core->revision = si476x_core_fwver_to_revision(core, info.func,
633*4882a593Smuzhiyun 						       info.firmware.major,
634*4882a593Smuzhiyun 						       info.firmware.minor[0],
635*4882a593Smuzhiyun 						       info.firmware.minor[1]);
636*4882a593Smuzhiyun power_down:
637*4882a593Smuzhiyun 	si476x_core_set_power_state(core, SI476X_POWER_DOWN);
638*4882a593Smuzhiyun exit:
639*4882a593Smuzhiyun 	si476x_core_unlock(core);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return rval;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
si476x_core_has_am(struct si476x_core * core)644*4882a593Smuzhiyun bool si476x_core_has_am(struct si476x_core *core)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	return core->chip_id == SI476X_CHIP_SI4761 ||
647*4882a593Smuzhiyun 		core->chip_id == SI476X_CHIP_SI4764;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_has_am);
650*4882a593Smuzhiyun 
si476x_core_has_diversity(struct si476x_core * core)651*4882a593Smuzhiyun bool si476x_core_has_diversity(struct si476x_core *core)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	return core->chip_id == SI476X_CHIP_SI4764;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_has_diversity);
656*4882a593Smuzhiyun 
si476x_core_is_a_secondary_tuner(struct si476x_core * core)657*4882a593Smuzhiyun bool si476x_core_is_a_secondary_tuner(struct si476x_core *core)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	return si476x_core_has_diversity(core) &&
660*4882a593Smuzhiyun 		(core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA ||
661*4882a593Smuzhiyun 		 core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING);
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner);
664*4882a593Smuzhiyun 
si476x_core_is_a_primary_tuner(struct si476x_core * core)665*4882a593Smuzhiyun bool si476x_core_is_a_primary_tuner(struct si476x_core *core)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	return si476x_core_has_diversity(core) &&
668*4882a593Smuzhiyun 		(core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA ||
669*4882a593Smuzhiyun 		 core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner);
672*4882a593Smuzhiyun 
si476x_core_is_in_am_receiver_mode(struct si476x_core * core)673*4882a593Smuzhiyun bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	return si476x_core_has_am(core) &&
676*4882a593Smuzhiyun 		(core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER);
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode);
679*4882a593Smuzhiyun 
si476x_core_is_powered_up(struct si476x_core * core)680*4882a593Smuzhiyun bool si476x_core_is_powered_up(struct si476x_core *core)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun 	return core->power_state == SI476X_POWER_UP_FULL;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(si476x_core_is_powered_up);
685*4882a593Smuzhiyun 
si476x_core_probe(struct i2c_client * client,const struct i2c_device_id * id)686*4882a593Smuzhiyun static int si476x_core_probe(struct i2c_client *client,
687*4882a593Smuzhiyun 			     const struct i2c_device_id *id)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	int rval;
690*4882a593Smuzhiyun 	struct si476x_core          *core;
691*4882a593Smuzhiyun 	struct si476x_platform_data *pdata;
692*4882a593Smuzhiyun 	struct mfd_cell *cell;
693*4882a593Smuzhiyun 	int              cell_num;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL);
696*4882a593Smuzhiyun 	if (!core)
697*4882a593Smuzhiyun 		return -ENOMEM;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	core->client = client;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	core->regmap = devm_regmap_init_si476x(core);
702*4882a593Smuzhiyun 	if (IS_ERR(core->regmap)) {
703*4882a593Smuzhiyun 		rval = PTR_ERR(core->regmap);
704*4882a593Smuzhiyun 		dev_err(&client->dev,
705*4882a593Smuzhiyun 			"Failed to allocate register map: %d\n",
706*4882a593Smuzhiyun 			rval);
707*4882a593Smuzhiyun 		return rval;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	i2c_set_clientdata(client, core);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	atomic_set(&core->is_alive, 0);
713*4882a593Smuzhiyun 	core->power_state = SI476X_POWER_DOWN;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	pdata = dev_get_platdata(&client->dev);
716*4882a593Smuzhiyun 	if (pdata) {
717*4882a593Smuzhiyun 		memcpy(&core->power_up_parameters,
718*4882a593Smuzhiyun 		       &pdata->power_up_parameters,
719*4882a593Smuzhiyun 		       sizeof(core->power_up_parameters));
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 		core->gpio_reset = -1;
722*4882a593Smuzhiyun 		if (gpio_is_valid(pdata->gpio_reset)) {
723*4882a593Smuzhiyun 			rval = gpio_request(pdata->gpio_reset, "si476x reset");
724*4882a593Smuzhiyun 			if (rval) {
725*4882a593Smuzhiyun 				dev_err(&client->dev,
726*4882a593Smuzhiyun 					"Failed to request gpio: %d\n", rval);
727*4882a593Smuzhiyun 				return rval;
728*4882a593Smuzhiyun 			}
729*4882a593Smuzhiyun 			core->gpio_reset = pdata->gpio_reset;
730*4882a593Smuzhiyun 			gpio_direction_output(core->gpio_reset, 0);
731*4882a593Smuzhiyun 		}
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		core->diversity_mode = pdata->diversity_mode;
734*4882a593Smuzhiyun 		memcpy(&core->pinmux, &pdata->pinmux,
735*4882a593Smuzhiyun 		       sizeof(struct si476x_pinmux));
736*4882a593Smuzhiyun 	} else {
737*4882a593Smuzhiyun 		dev_err(&client->dev, "No platform data provided\n");
738*4882a593Smuzhiyun 		return -EINVAL;
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	core->supplies[0].supply = "vd";
742*4882a593Smuzhiyun 	core->supplies[1].supply = "va";
743*4882a593Smuzhiyun 	core->supplies[2].supply = "vio1";
744*4882a593Smuzhiyun 	core->supplies[3].supply = "vio2";
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	rval = devm_regulator_bulk_get(&client->dev,
747*4882a593Smuzhiyun 				       ARRAY_SIZE(core->supplies),
748*4882a593Smuzhiyun 				       core->supplies);
749*4882a593Smuzhiyun 	if (rval) {
750*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to get all of the regulators\n");
751*4882a593Smuzhiyun 		goto free_gpio;
752*4882a593Smuzhiyun 	}
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	mutex_init(&core->cmd_lock);
755*4882a593Smuzhiyun 	init_waitqueue_head(&core->command);
756*4882a593Smuzhiyun 	init_waitqueue_head(&core->tuning);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	rval = kfifo_alloc(&core->rds_fifo,
759*4882a593Smuzhiyun 			   SI476X_DRIVER_RDS_FIFO_DEPTH *
760*4882a593Smuzhiyun 			   sizeof(struct v4l2_rds_data),
761*4882a593Smuzhiyun 			   GFP_KERNEL);
762*4882a593Smuzhiyun 	if (rval) {
763*4882a593Smuzhiyun 		dev_err(&client->dev, "Could not allocate the FIFO\n");
764*4882a593Smuzhiyun 		goto free_gpio;
765*4882a593Smuzhiyun 	}
766*4882a593Smuzhiyun 	mutex_init(&core->rds_drainer_status_lock);
767*4882a593Smuzhiyun 	init_waitqueue_head(&core->rds_read_queue);
768*4882a593Smuzhiyun 	INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (client->irq) {
771*4882a593Smuzhiyun 		rval = devm_request_threaded_irq(&client->dev,
772*4882a593Smuzhiyun 						 client->irq, NULL,
773*4882a593Smuzhiyun 						 si476x_core_interrupt,
774*4882a593Smuzhiyun 						 IRQF_TRIGGER_FALLING |
775*4882a593Smuzhiyun 						 IRQF_ONESHOT,
776*4882a593Smuzhiyun 						 client->name, core);
777*4882a593Smuzhiyun 		if (rval < 0) {
778*4882a593Smuzhiyun 			dev_err(&client->dev, "Could not request IRQ %d\n",
779*4882a593Smuzhiyun 				client->irq);
780*4882a593Smuzhiyun 			goto free_kfifo;
781*4882a593Smuzhiyun 		}
782*4882a593Smuzhiyun 		disable_irq(client->irq);
783*4882a593Smuzhiyun 		dev_dbg(&client->dev, "IRQ requested.\n");
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 		core->rds_fifo_depth = 20;
786*4882a593Smuzhiyun 	} else {
787*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&core->status_monitor,
788*4882a593Smuzhiyun 				  si476x_core_poll_loop);
789*4882a593Smuzhiyun 		dev_info(&client->dev,
790*4882a593Smuzhiyun 			 "No IRQ number specified, will use polling\n");
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		core->rds_fifo_depth = 5;
793*4882a593Smuzhiyun 	}
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	core->chip_id = id->driver_data;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	rval = si476x_core_get_revision_info(core);
798*4882a593Smuzhiyun 	if (rval < 0) {
799*4882a593Smuzhiyun 		rval = -ENODEV;
800*4882a593Smuzhiyun 		goto free_kfifo;
801*4882a593Smuzhiyun 	}
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	cell_num = 0;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	cell = &core->cells[SI476X_RADIO_CELL];
806*4882a593Smuzhiyun 	cell->name = "si476x-radio";
807*4882a593Smuzhiyun 	cell_num++;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun #ifdef CONFIG_SND_SOC_SI476X
810*4882a593Smuzhiyun 	if ((core->chip_id == SI476X_CHIP_SI4761 ||
811*4882a593Smuzhiyun 	     core->chip_id == SI476X_CHIP_SI4764)	&&
812*4882a593Smuzhiyun 	    core->pinmux.dclk == SI476X_DCLK_DAUDIO     &&
813*4882a593Smuzhiyun 	    core->pinmux.dfs  == SI476X_DFS_DAUDIO      &&
814*4882a593Smuzhiyun 	    core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT &&
815*4882a593Smuzhiyun 	    core->pinmux.xout == SI476X_XOUT_TRISTATE) {
816*4882a593Smuzhiyun 		cell = &core->cells[SI476X_CODEC_CELL];
817*4882a593Smuzhiyun 		cell->name          = "si476x-codec";
818*4882a593Smuzhiyun 		cell_num++;
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun #endif
821*4882a593Smuzhiyun 	rval = mfd_add_devices(&client->dev,
822*4882a593Smuzhiyun 			       (client->adapter->nr << 8) + client->addr,
823*4882a593Smuzhiyun 			       core->cells, cell_num,
824*4882a593Smuzhiyun 			       NULL, 0, NULL);
825*4882a593Smuzhiyun 	if (!rval)
826*4882a593Smuzhiyun 		return 0;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun free_kfifo:
829*4882a593Smuzhiyun 	kfifo_free(&core->rds_fifo);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun free_gpio:
832*4882a593Smuzhiyun 	if (gpio_is_valid(core->gpio_reset))
833*4882a593Smuzhiyun 		gpio_free(core->gpio_reset);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	return rval;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
si476x_core_remove(struct i2c_client * client)838*4882a593Smuzhiyun static int si476x_core_remove(struct i2c_client *client)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	struct si476x_core *core = i2c_get_clientdata(client);
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	si476x_core_pronounce_dead(core);
843*4882a593Smuzhiyun 	mfd_remove_devices(&client->dev);
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	if (client->irq)
846*4882a593Smuzhiyun 		disable_irq(client->irq);
847*4882a593Smuzhiyun 	else
848*4882a593Smuzhiyun 		cancel_delayed_work_sync(&core->status_monitor);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	kfifo_free(&core->rds_fifo);
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	if (gpio_is_valid(core->gpio_reset))
853*4882a593Smuzhiyun 		gpio_free(core->gpio_reset);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return 0;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun static const struct i2c_device_id si476x_id[] = {
860*4882a593Smuzhiyun 	{ "si4761", SI476X_CHIP_SI4761 },
861*4882a593Smuzhiyun 	{ "si4764", SI476X_CHIP_SI4764 },
862*4882a593Smuzhiyun 	{ "si4768", SI476X_CHIP_SI4768 },
863*4882a593Smuzhiyun 	{ },
864*4882a593Smuzhiyun };
865*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si476x_id);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun static struct i2c_driver si476x_core_driver = {
868*4882a593Smuzhiyun 	.driver		= {
869*4882a593Smuzhiyun 		.name	= "si476x-core",
870*4882a593Smuzhiyun 	},
871*4882a593Smuzhiyun 	.probe		= si476x_core_probe,
872*4882a593Smuzhiyun 	.remove         = si476x_core_remove,
873*4882a593Smuzhiyun 	.id_table       = si476x_id,
874*4882a593Smuzhiyun };
875*4882a593Smuzhiyun module_i2c_driver(si476x_core_driver);
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
879*4882a593Smuzhiyun MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver");
880*4882a593Smuzhiyun MODULE_LICENSE("GPL");
881