// SPDX-License-Identifier: GPL-2.0-only /* * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD * device * * Copyright (C) 2012 Innovative Converged Devices(ICD) * Copyright (C) 2013 Andrey Smirnov * * Author: Andrey Smirnov <[email protected]> */ #include <linux/module.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/mfd/si476x-core.h> #define SI476X_MAX_IO_ERRORS … #define SI476X_DRIVER_RDS_FIFO_DEPTH … /** * si476x_core_config_pinmux() - pin function configuration function * * @core: Core device structure * * Configure the functions of the pins of the radio chip. * * The function returns zero in case of succes or negative error code * otherwise. */ static int si476x_core_config_pinmux(struct si476x_core *core) { … } static inline void si476x_core_schedule_polling_work(struct si476x_core *core) { … } /** * si476x_core_start() - early chip startup function * @core: Core device structure * @soft: When set, this flag forces "soft" startup, where "soft" * power down is the one done by sending appropriate command instead * of using reset pin of the tuner * * Perform required startup sequence to correctly power * up the chip and perform initial configuration. It does the * following sequence of actions: * 1. Claims and enables the power supplies VD and VIO1 required * for I2C interface of the chip operation. * 2. Waits for 100us, pulls the reset line up, enables irq, * waits for another 100us as it is specified by the * datasheet. * 3. Sends 'POWER_UP' command to the device with all provided * information about power-up parameters. * 4. Configures, pin multiplexor, disables digital audio and * configures interrupt sources. * * The function returns zero in case of succes or negative error code * otherwise. */ int si476x_core_start(struct si476x_core *core, bool soft) { … } EXPORT_SYMBOL_GPL(…); /** * si476x_core_stop() - chip power-down function * @core: Core device structure * @soft: When set, function sends a POWER_DOWN command instead of * bringing reset line low * * Power down the chip by performing following actions: * 1. Disable IRQ or stop the polling worker * 2. Send the POWER_DOWN command if the power down is soft or bring * reset line low if not. * * The function returns zero in case of succes or negative error code * otherwise. */ int si476x_core_stop(struct si476x_core *core, bool soft) { … } EXPORT_SYMBOL_GPL(…); /** * si476x_core_set_power_state() - set the level at which the power is * supplied for the chip. * @core: Core device structure * @next_state: enum si476x_power_state describing power state to * switch to. * * Switch on all the required power supplies * * This function returns 0 in case of suvccess and negative error code * otherwise. */ int si476x_core_set_power_state(struct si476x_core *core, enum si476x_power_state next_state) { … } EXPORT_SYMBOL_GPL(…); /** * si476x_core_report_drainer_stop() - mark the completion of the RDS * buffer drain porcess by the worker. * * @core: Core device structure */ static inline void si476x_core_report_drainer_stop(struct si476x_core *core) { … } /** * si476x_core_start_rds_drainer_once() - start RDS drainer worker if * ther is none working, do nothing otherwise * * @core: Datastructure corresponding to the chip. */ static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) { … } /** * si476x_core_drain_rds_fifo() - RDS buffer drainer. * @work: struct work_struct being ppassed to the function by the * kernel. * * Drain the contents of the RDS FIFO of */ static void si476x_core_drain_rds_fifo(struct work_struct *work) { … } /** * si476x_core_pronounce_dead() * * @core: Core device structure * * Mark the device as being dead and wake up all potentially waiting * threads of execution. * */ static void si476x_core_pronounce_dead(struct si476x_core *core) { … } /** * si476x_core_i2c_xfer() * * @core: Core device structure * @type: Transfer type * @buf: Transfer buffer for/with data * @count: Transfer buffer size * * Perfrom and I2C transfer(either read or write) and keep a counter * of I/O errors. If the error counter rises above the threshold * pronounce device dead. * * The function returns zero on succes or negative error code on * failure. */ int si476x_core_i2c_xfer(struct si476x_core *core, enum si476x_i2c_type type, char *buf, int count) { … } EXPORT_SYMBOL_GPL(…); /** * si476x_core_get_status() * @core: Core device structure * * Get the status byte of the core device by berforming one byte I2C * read. * * The function returns a status value or a negative error code on * error. */ static int si476x_core_get_status(struct si476x_core *core) { … } /** * si476x_core_get_and_signal_status() - IRQ dispatcher * @core: Core device structure * * Dispatch the arrived interrupt request based on the value of the * status byte reported by the tuner. * */ static void si476x_core_get_and_signal_status(struct si476x_core *core) { … } static void si476x_core_poll_loop(struct work_struct *work) { … } static irqreturn_t si476x_core_interrupt(int irq, void *dev) { … } /** * si476x_core_fwver_to_revision() * @core: Core device structure * @func: Selects the boot function of the device: * *_BOOTLOADER - Boot loader * *_FM_RECEIVER - FM receiver * *_AM_RECEIVER - AM receiver * *_WB_RECEIVER - Weatherband receiver * @major: Firmware major number * @minor1: Firmware first minor number * @minor2: Firmware second minor number * * Convert a chip's firmware version number into an offset that later * will be used to as offset in "vtable" of tuner functions * * This function returns a positive offset in case of success and a -1 * in case of failure. */ static int si476x_core_fwver_to_revision(struct si476x_core *core, int func, int major, int minor1, int minor2) { … } /** * si476x_core_get_revision_info() * @core: Core device structure * * Get the firmware version number of the device. It is done in * following three steps: * 1. Power-up the device * 2. Send the 'FUNC_INFO' command * 3. Powering the device down. * * The function return zero on success and a negative error code on * failure. */ static int si476x_core_get_revision_info(struct si476x_core *core) { … } bool si476x_core_has_am(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); bool si476x_core_has_diversity(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); bool si476x_core_is_a_primary_tuner(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); bool si476x_core_is_powered_up(struct si476x_core *core) { … } EXPORT_SYMBOL_GPL(…); static int si476x_core_probe(struct i2c_client *client) { … } static void si476x_core_remove(struct i2c_client *client) { … } static const struct i2c_device_id si476x_id[] = …; MODULE_DEVICE_TABLE(i2c, si476x_id); static struct i2c_driver si476x_core_driver = …; module_i2c_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;