cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wl1273-core.c (5834B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * MFD driver for wl1273 FM radio and audio codec submodules.
      4 *
      5 * Copyright (C) 2011 Nokia Corporation
      6 * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
      7 */
      8
      9#include <linux/mfd/wl1273-core.h>
     10#include <linux/slab.h>
     11#include <linux/module.h>
     12
     13#define DRIVER_DESC "WL1273 FM Radio Core"
     14
     15static const struct i2c_device_id wl1273_driver_id_table[] = {
     16	{ WL1273_FM_DRIVER_NAME, 0 },
     17	{ }
     18};
     19MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
     20
     21static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
     22{
     23	struct i2c_client *client = core->client;
     24	u8 b[2];
     25	int r;
     26
     27	r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
     28	if (r != 2) {
     29		dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
     30		return -EREMOTEIO;
     31	}
     32
     33	*value = (u16)b[0] << 8 | b[1];
     34
     35	return 0;
     36}
     37
     38static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
     39{
     40	struct i2c_client *client = core->client;
     41	u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
     42	int r;
     43
     44	r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
     45	if (r) {
     46		dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
     47		return r;
     48	}
     49
     50	return 0;
     51}
     52
     53static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
     54{
     55	struct i2c_client *client = core->client;
     56	struct i2c_msg msg;
     57	int r;
     58
     59	msg.addr = client->addr;
     60	msg.flags = 0;
     61	msg.buf = data;
     62	msg.len = len;
     63
     64	r = i2c_transfer(client->adapter, &msg, 1);
     65	if (r != 1) {
     66		dev_err(&client->dev, "%s: write error.\n", __func__);
     67		return -EREMOTEIO;
     68	}
     69
     70	return 0;
     71}
     72
     73/**
     74 * wl1273_fm_set_audio() -	Set audio mode.
     75 * @core:			A pointer to the device struct.
     76 * @new_mode:			The new audio mode.
     77 *
     78 * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
     79 */
     80static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
     81{
     82	int r = 0;
     83
     84	if (core->mode == WL1273_MODE_OFF ||
     85	    core->mode == WL1273_MODE_SUSPENDED)
     86		return -EPERM;
     87
     88	if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
     89		r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
     90					WL1273_PCM_DEF_MODE);
     91		if (r)
     92			goto out;
     93
     94		r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
     95					core->i2s_mode);
     96		if (r)
     97			goto out;
     98
     99		r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
    100					WL1273_AUDIO_ENABLE_I2S);
    101		if (r)
    102			goto out;
    103
    104	} else if (core->mode == WL1273_MODE_RX &&
    105		   new_mode == WL1273_AUDIO_ANALOG) {
    106		r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
    107					WL1273_AUDIO_ENABLE_ANALOG);
    108		if (r)
    109			goto out;
    110
    111	} else if (core->mode == WL1273_MODE_TX &&
    112		   new_mode == WL1273_AUDIO_DIGITAL) {
    113		r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
    114					core->i2s_mode);
    115		if (r)
    116			goto out;
    117
    118		r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
    119					WL1273_AUDIO_IO_SET_I2S);
    120		if (r)
    121			goto out;
    122
    123	} else if (core->mode == WL1273_MODE_TX &&
    124		   new_mode == WL1273_AUDIO_ANALOG) {
    125		r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
    126					WL1273_AUDIO_IO_SET_ANALOG);
    127		if (r)
    128			goto out;
    129	}
    130
    131	core->audio_mode = new_mode;
    132out:
    133	return r;
    134}
    135
    136/**
    137 * wl1273_fm_set_volume() -	Set volume.
    138 * @core:			A pointer to the device struct.
    139 * @volume:			The new volume value.
    140 */
    141static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
    142{
    143	int r;
    144
    145	if (volume > WL1273_MAX_VOLUME)
    146		return -EINVAL;
    147
    148	if (core->volume == volume)
    149		return 0;
    150
    151	r = wl1273_fm_write_cmd(core, WL1273_VOLUME_SET, volume);
    152	if (r)
    153		return r;
    154
    155	core->volume = volume;
    156	return 0;
    157}
    158
    159static int wl1273_core_probe(struct i2c_client *client,
    160				       const struct i2c_device_id *id)
    161{
    162	struct wl1273_fm_platform_data *pdata = dev_get_platdata(&client->dev);
    163	struct wl1273_core *core;
    164	struct mfd_cell *cell;
    165	int children = 0;
    166	int r = 0;
    167
    168	dev_dbg(&client->dev, "%s\n", __func__);
    169
    170	if (!pdata) {
    171		dev_err(&client->dev, "No platform data.\n");
    172		return -EINVAL;
    173	}
    174
    175	if (!(pdata->children & WL1273_RADIO_CHILD)) {
    176		dev_err(&client->dev, "Cannot function without radio child.\n");
    177		return -EINVAL;
    178	}
    179
    180	core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL);
    181	if (!core)
    182		return -ENOMEM;
    183
    184	core->pdata = pdata;
    185	core->client = client;
    186	mutex_init(&core->lock);
    187
    188	i2c_set_clientdata(client, core);
    189
    190	dev_dbg(&client->dev, "%s: Have V4L2.\n", __func__);
    191
    192	cell = &core->cells[children];
    193	cell->name = "wl1273_fm_radio";
    194	cell->platform_data = &core;
    195	cell->pdata_size = sizeof(core);
    196	children++;
    197
    198	core->read = wl1273_fm_read_reg;
    199	core->write = wl1273_fm_write_cmd;
    200	core->write_data = wl1273_fm_write_data;
    201	core->set_audio = wl1273_fm_set_audio;
    202	core->set_volume = wl1273_fm_set_volume;
    203
    204	if (pdata->children & WL1273_CODEC_CHILD) {
    205		cell = &core->cells[children];
    206
    207		dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
    208		cell->name = "wl1273-codec";
    209		cell->platform_data = &core;
    210		cell->pdata_size = sizeof(core);
    211		children++;
    212	}
    213
    214	dev_dbg(&client->dev, "%s: number of children: %d.\n",
    215		__func__, children);
    216
    217	r = devm_mfd_add_devices(&client->dev, -1, core->cells,
    218				 children, NULL, 0, NULL);
    219	if (r)
    220		goto err;
    221
    222	return 0;
    223
    224err:
    225	pdata->free_resources();
    226
    227	dev_dbg(&client->dev, "%s\n", __func__);
    228
    229	return r;
    230}
    231
    232static struct i2c_driver wl1273_core_driver = {
    233	.driver = {
    234		.name = WL1273_FM_DRIVER_NAME,
    235	},
    236	.probe = wl1273_core_probe,
    237	.id_table = wl1273_driver_id_table,
    238};
    239
    240static int __init wl1273_core_init(void)
    241{
    242	int r;
    243
    244	r = i2c_add_driver(&wl1273_core_driver);
    245	if (r) {
    246		pr_err(WL1273_FM_DRIVER_NAME
    247		       ": driver registration failed\n");
    248		return r;
    249	}
    250
    251	return r;
    252}
    253
    254static void __exit wl1273_core_exit(void)
    255{
    256	i2c_del_driver(&wl1273_core_driver);
    257}
    258late_initcall(wl1273_core_init);
    259module_exit(wl1273_core_exit);
    260
    261MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
    262MODULE_DESCRIPTION(DRIVER_DESC);
    263MODULE_LICENSE("GPL");