linux/drivers/mfd/wl1273-core.c
<<
>>
Prefs
   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");
 264