linux/sound/soc/codecs/zl38060.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2//
   3// Codec driver for Microsemi ZL38060 Connected Home Audio Processor.
   4//
   5// Copyright(c) 2020 Sven Van Asbroeck
   6
   7// The ZL38060 is very flexible and configurable. This driver implements only a
   8// tiny subset of the chip's possible configurations:
   9//
  10// - DSP block bypassed: DAI        routed straight to DACs
  11//                       microphone routed straight to DAI
  12// - chip's internal clock is driven by a 12 MHz external crystal
  13// - chip's DAI connected to CPU is I2S, and bit + frame clock master
  14// - chip must be strapped for "host boot": in this mode, firmware will be
  15//   provided by this driver.
  16
  17#include <linux/gpio/consumer.h>
  18#include <linux/gpio/driver.h>
  19#include <linux/property.h>
  20#include <linux/spi/spi.h>
  21#include <linux/regmap.h>
  22#include <linux/module.h>
  23#include <linux/ihex.h>
  24
  25#include <sound/pcm_params.h>
  26#include <sound/core.h>
  27#include <sound/pcm.h>
  28#include <sound/soc.h>
  29
  30#define DRV_NAME                "zl38060"
  31
  32#define ZL38_RATES              (SNDRV_PCM_RATE_8000  |\
  33                                SNDRV_PCM_RATE_16000 |\
  34                                SNDRV_PCM_RATE_48000)
  35#define ZL38_FORMATS            SNDRV_PCM_FMTBIT_S16_LE
  36
  37#define HBI_FIRMWARE_PAGE       0xFF
  38#define ZL38_MAX_RAW_XFER       0x100
  39
  40#define REG_TDMA_CFG_CLK        0x0262
  41#define CFG_CLK_PCLK_SHIFT      4
  42#define CFG_CLK_PCLK_MASK       (0x7ff << CFG_CLK_PCLK_SHIFT)
  43#define CFG_CLK_PCLK(bits)      ((bits - 1) << CFG_CLK_PCLK_SHIFT)
  44#define CFG_CLK_MASTER          BIT(15)
  45#define CFG_CLK_FSRATE_MASK     0x7
  46#define CFG_CLK_FSRATE_8KHZ     0x1
  47#define CFG_CLK_FSRATE_16KHZ    0x2
  48#define CFG_CLK_FSRATE_48KHZ    0x6
  49
  50#define REG_CLK_CFG             0x0016
  51#define CLK_CFG_SOURCE_XTAL     BIT(15)
  52
  53#define REG_CLK_STATUS          0x0014
  54#define CLK_STATUS_HWRST        BIT(0)
  55
  56#define REG_PARAM_RESULT        0x0034
  57#define PARAM_RESULT_READY      0xD3D3
  58
  59#define REG_PG255_BASE_HI       0x000C
  60#define REG_PG255_OFFS(addr)    ((HBI_FIRMWARE_PAGE << 8) | (addr & 0xFF))
  61#define REG_FWR_EXEC            0x012C
  62
  63#define REG_CMD                 0x0032
  64#define REG_HW_REV              0x0020
  65#define REG_FW_PROD             0x0022
  66#define REG_FW_REV              0x0024
  67
  68#define REG_SEMA_FLAGS          0x0006
  69#define SEMA_FLAGS_BOOT_CMD     BIT(0)
  70#define SEMA_FLAGS_APP_REBOOT   BIT(1)
  71
  72#define REG_HW_REV              0x0020
  73#define REG_FW_PROD             0x0022
  74#define REG_FW_REV              0x0024
  75#define REG_GPIO_DIR            0x02DC
  76#define REG_GPIO_DAT            0x02DA
  77
  78#define BOOTCMD_LOAD_COMPLETE   0x000D
  79#define BOOTCMD_FW_GO           0x0008
  80
  81#define FIRMWARE_MAJOR          2
  82#define FIRMWARE_MINOR          2
  83
  84struct zl38_codec_priv {
  85        struct device *dev;
  86        struct regmap *regmap;
  87        bool is_stream_in_use[2];
  88        struct gpio_chip *gpio_chip;
  89};
  90
  91static int zl38_fw_issue_command(struct regmap *regmap, u16 cmd)
  92{
  93        unsigned int val;
  94        int err;
  95
  96        err = regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
  97                                       !(val & SEMA_FLAGS_BOOT_CMD), 10000,
  98                                       10000 * 100);
  99        if (err)
 100                return err;
 101        err = regmap_write(regmap, REG_CMD, cmd);
 102        if (err)
 103                return err;
 104        err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_BOOT_CMD,
 105                                 SEMA_FLAGS_BOOT_CMD);
 106        if (err)
 107                return err;
 108
 109        return regmap_read_poll_timeout(regmap, REG_CMD, val, !val, 10000,
 110                                        10000 * 100);
 111}
 112
 113static int zl38_fw_go(struct regmap *regmap)
 114{
 115        int err;
 116
 117        err = zl38_fw_issue_command(regmap, BOOTCMD_LOAD_COMPLETE);
 118        if (err)
 119                return err;
 120
 121        return zl38_fw_issue_command(regmap, BOOTCMD_FW_GO);
 122}
 123
 124static int zl38_fw_enter_boot_mode(struct regmap *regmap)
 125{
 126        unsigned int val;
 127        int err;
 128
 129        err = regmap_update_bits(regmap, REG_CLK_STATUS, CLK_STATUS_HWRST,
 130                                 CLK_STATUS_HWRST);
 131        if (err)
 132                return err;
 133
 134        return regmap_read_poll_timeout(regmap, REG_PARAM_RESULT, val,
 135                                        val == PARAM_RESULT_READY, 1000, 50000);
 136}
 137
 138static int
 139zl38_fw_send_data(struct regmap *regmap, u32 addr, const void *data, u16 len)
 140{
 141        __be32 addr_base = cpu_to_be32(addr & ~0xFF);
 142        int err;
 143
 144        err = regmap_raw_write(regmap, REG_PG255_BASE_HI, &addr_base,
 145                               sizeof(addr_base));
 146        if (err)
 147                return err;
 148        return regmap_raw_write(regmap, REG_PG255_OFFS(addr), data, len);
 149}
 150
 151static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data)
 152{
 153        /* execution address from ihex: 32-bit little endian.
 154         * device register expects 32-bit big endian.
 155         */
 156        u32 addr = le32_to_cpup(data);
 157        __be32 baddr = cpu_to_be32(addr);
 158
 159        return regmap_raw_write(regmap, REG_FWR_EXEC, &baddr, sizeof(baddr));
 160}
 161
 162static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
 163{
 164        const struct ihex_binrec *rec;
 165        const struct firmware *fw;
 166        u32 addr;
 167        u16 len;
 168        int err;
 169
 170        /* how to get this firmware:
 171         * 1. request and download chip firmware from Microsemi
 172         *    (provided by Microsemi in srec format)
 173         * 2. convert downloaded firmware from srec to ihex. Simple tool:
 174         *    https://gitlab.com/TheSven73/s3-to-irec
 175         * 3. convert ihex to binary (.fw) using ihex2fw tool which is included
 176         *    with the Linux kernel sources
 177         */
 178        err = request_ihex_firmware(&fw, "zl38060.fw", dev);
 179        if (err)
 180                return err;
 181        err = zl38_fw_enter_boot_mode(regmap);
 182        if (err)
 183                goto out;
 184        rec = (const struct ihex_binrec *)fw->data;
 185        while (rec) {
 186                addr = be32_to_cpu(rec->addr);
 187                len = be16_to_cpu(rec->len);
 188                if (addr) {
 189                        /* regular data ihex record */
 190                        err = zl38_fw_send_data(regmap, addr, rec->data, len);
 191                } else if (len == 4) {
 192                        /* execution address ihex record */
 193                        err = zl38_fw_send_xaddr(regmap, rec->data);
 194                } else {
 195                        err = -EINVAL;
 196                }
 197                if (err)
 198                        goto out;
 199                /* next ! */
 200                rec = ihex_next_binrec(rec);
 201        }
 202        err = zl38_fw_go(regmap);
 203
 204out:
 205        release_firmware(fw);
 206        return err;
 207}
 208
 209
 210static int zl38_software_reset(struct regmap *regmap)
 211{
 212        unsigned int val;
 213        int err;
 214
 215        err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_APP_REBOOT,
 216                                 SEMA_FLAGS_APP_REBOOT);
 217        if (err)
 218                return err;
 219
 220        /* wait for host bus interface to settle.
 221         * Not sure if this is required: Microsemi's vendor driver does this,
 222         * but the firmware manual does not mention it. Leave it in, there's
 223         * little downside, apart from a slower reset.
 224         */
 225        msleep(50);
 226
 227        return regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
 228                                        !(val & SEMA_FLAGS_APP_REBOOT), 10000,
 229                                        10000 * 100);
 230}
 231
 232static int zl38_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 233{
 234        struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
 235        int err;
 236
 237        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 238        case SND_SOC_DAIFMT_I2S:
 239                /* firmware default is normal i2s */
 240                break;
 241        default:
 242                return -EINVAL;
 243        }
 244
 245        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 246        case SND_SOC_DAIFMT_NB_NF:
 247                /* firmware default is normal bitclock and frame */
 248                break;
 249        default:
 250                return -EINVAL;
 251        }
 252
 253        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 254        case SND_SOC_DAIFMT_CBM_CFM:
 255                /* always 32 bits per frame (= 16 bits/channel, 2 channels) */
 256                err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
 257                                         CFG_CLK_MASTER | CFG_CLK_PCLK_MASK,
 258                                         CFG_CLK_MASTER | CFG_CLK_PCLK(32));
 259                if (err)
 260                        return err;
 261                break;
 262        default:
 263                return -EINVAL;
 264        }
 265
 266        return 0;
 267}
 268
 269static int zl38_hw_params(struct snd_pcm_substream *substream,
 270                          struct snd_pcm_hw_params *params,
 271                          struct snd_soc_dai *dai)
 272{
 273        struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
 274        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 275        unsigned int fsrate;
 276        int err;
 277
 278        /* We cannot change hw_params while the dai is already in use - the
 279         * software reset will corrupt the audio. However, this is not required,
 280         * as the chip's TDM buses are fully symmetric, which mandates identical
 281         * rates, channels, and samplebits for record and playback.
 282         */
 283        if (priv->is_stream_in_use[!tx])
 284                goto skip_setup;
 285
 286        switch (params_rate(params)) {
 287        case 8000:
 288                fsrate = CFG_CLK_FSRATE_8KHZ;
 289                break;
 290        case 16000:
 291                fsrate = CFG_CLK_FSRATE_16KHZ;
 292                break;
 293        case 48000:
 294                fsrate = CFG_CLK_FSRATE_48KHZ;
 295                break;
 296        default:
 297                return -EINVAL;
 298        }
 299
 300        err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
 301                                 CFG_CLK_FSRATE_MASK, fsrate);
 302        if (err)
 303                return err;
 304
 305        /* chip requires a software reset to apply audio register changes */
 306        err = zl38_software_reset(priv->regmap);
 307        if (err)
 308                return err;
 309
 310skip_setup:
 311        priv->is_stream_in_use[tx] = true;
 312
 313        return 0;
 314}
 315
 316static int zl38_hw_free(struct snd_pcm_substream *substream,
 317                        struct snd_soc_dai *dai)
 318{
 319        struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
 320        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 321
 322        priv->is_stream_in_use[tx] = false;
 323
 324        return 0;
 325}
 326
 327/* stereo bypass with no AEC */
 328static const struct reg_sequence cp_config_stereo_bypass[] = {
 329        /* interconnects must be programmed first */
 330        { 0x0210, 0x0005 },     /* DAC1   in <= I2S1-L */
 331        { 0x0212, 0x0006 },     /* DAC2   in <= I2S1-R */
 332        { 0x0214, 0x0001 },     /* I2S1-L in <= MIC1   */
 333        { 0x0216, 0x0001 },     /* I2S1-R in <= MIC1   */
 334        { 0x0224, 0x0000 },     /* AEC-S  in <= n/a    */
 335        { 0x0226, 0x0000 },     /* AEC-R  in <= n/a    */
 336        /* output enables must be programmed next */
 337        { 0x0202, 0x000F },     /* enable I2S1 + DAC   */
 338};
 339
 340static const struct snd_soc_dai_ops zl38_dai_ops = {
 341        .set_fmt = zl38_set_fmt,
 342        .hw_params = zl38_hw_params,
 343        .hw_free = zl38_hw_free,
 344};
 345
 346static struct snd_soc_dai_driver zl38_dai = {
 347        .name = "zl38060-tdma",
 348        .playback = {
 349                .stream_name = "Playback",
 350                .channels_min = 2,
 351                .channels_max = 2,
 352                .rates = ZL38_RATES,
 353                .formats = ZL38_FORMATS,
 354        },
 355        .capture = {
 356                .stream_name = "Capture",
 357                .channels_min = 2,
 358                .channels_max = 2,
 359                .rates = ZL38_RATES,
 360                .formats = ZL38_FORMATS,
 361        },
 362        .ops = &zl38_dai_ops,
 363        .symmetric_rate = 1,
 364        .symmetric_sample_bits = 1,
 365        .symmetric_channels = 1,
 366};
 367
 368static const struct snd_soc_dapm_widget zl38_dapm_widgets[] = {
 369        SND_SOC_DAPM_OUTPUT("DAC1"),
 370        SND_SOC_DAPM_OUTPUT("DAC2"),
 371
 372        SND_SOC_DAPM_INPUT("DMICL"),
 373};
 374
 375static const struct snd_soc_dapm_route zl38_dapm_routes[] = {
 376        { "DAC1",  NULL, "Playback" },
 377        { "DAC2",  NULL, "Playback" },
 378
 379        { "Capture",  NULL, "DMICL" },
 380};
 381
 382static const struct snd_soc_component_driver zl38_component_dev = {
 383        .dapm_widgets           = zl38_dapm_widgets,
 384        .num_dapm_widgets       = ARRAY_SIZE(zl38_dapm_widgets),
 385        .dapm_routes            = zl38_dapm_routes,
 386        .num_dapm_routes        = ARRAY_SIZE(zl38_dapm_routes),
 387        .endianness             = 1,
 388        .non_legacy_dai_naming  = 1,
 389};
 390
 391static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
 392{
 393        struct regmap *regmap = gpiochip_get_data(c);
 394        unsigned int mask = BIT(offset);
 395
 396        regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
 397}
 398
 399static int chip_gpio_get(struct gpio_chip *c, unsigned int offset)
 400{
 401        struct regmap *regmap = gpiochip_get_data(c);
 402        unsigned int mask = BIT(offset);
 403        unsigned int val;
 404        int err;
 405
 406        err = regmap_read(regmap, REG_GPIO_DAT, &val);
 407        if (err)
 408                return err;
 409
 410        return !!(val & mask);
 411}
 412
 413static int chip_direction_input(struct gpio_chip *c, unsigned int offset)
 414{
 415        struct regmap *regmap = gpiochip_get_data(c);
 416        unsigned int mask = BIT(offset);
 417
 418        return regmap_update_bits(regmap, REG_GPIO_DIR, mask, 0);
 419}
 420
 421static int
 422chip_direction_output(struct gpio_chip *c, unsigned int offset, int val)
 423{
 424        struct regmap *regmap = gpiochip_get_data(c);
 425        unsigned int mask = BIT(offset);
 426
 427        chip_gpio_set(c, offset, val);
 428        return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask);
 429}
 430
 431static const struct gpio_chip template_chip = {
 432        .owner = THIS_MODULE,
 433        .label = DRV_NAME,
 434
 435        .base = -1,
 436        .ngpio = 14,
 437        .direction_input = chip_direction_input,
 438        .direction_output = chip_direction_output,
 439        .get = chip_gpio_get,
 440        .set = chip_gpio_set,
 441
 442        .can_sleep = true,
 443};
 444
 445static int zl38_check_revision(struct device *dev, struct regmap *regmap)
 446{
 447        unsigned int hwrev, fwprod, fwrev;
 448        int fw_major, fw_minor, fw_micro;
 449        int err;
 450
 451        err = regmap_read(regmap, REG_HW_REV, &hwrev);
 452        if (err)
 453                return err;
 454        err = regmap_read(regmap, REG_FW_PROD, &fwprod);
 455        if (err)
 456                return err;
 457        err = regmap_read(regmap, REG_FW_REV, &fwrev);
 458        if (err)
 459                return err;
 460
 461        fw_major = (fwrev >> 12) & 0xF;
 462        fw_minor = (fwrev >>  8) & 0xF;
 463        fw_micro = fwrev & 0xFF;
 464        dev_info(dev, "hw rev 0x%x, fw product code %d, firmware rev %d.%d.%d",
 465                 hwrev & 0x1F, fwprod, fw_major, fw_minor, fw_micro);
 466
 467        if (fw_major != FIRMWARE_MAJOR || fw_minor < FIRMWARE_MINOR) {
 468                dev_err(dev, "unsupported firmware. driver supports %d.%d",
 469                        FIRMWARE_MAJOR, FIRMWARE_MINOR);
 470                return -EINVAL;
 471        }
 472
 473        return 0;
 474}
 475
 476static int zl38_bus_read(void *context,
 477                         const void *reg_buf, size_t reg_size,
 478                         void *val_buf, size_t val_size)
 479{
 480        struct spi_device *spi = context;
 481        const u8 *reg_buf8 = reg_buf;
 482        size_t len = 0;
 483        u8 offs, page;
 484        u8 txbuf[4];
 485
 486        if (reg_size != 2 || val_size > ZL38_MAX_RAW_XFER)
 487                return -EINVAL;
 488
 489        offs = reg_buf8[1] >> 1;
 490        page = reg_buf8[0];
 491
 492        if (page) {
 493                txbuf[len++] = 0xFE;
 494                txbuf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
 495                txbuf[len++] = offs;
 496                txbuf[len++] = val_size / 2 - 1;
 497        } else {
 498                txbuf[len++] = offs | 0x80;
 499                txbuf[len++] = val_size / 2 - 1;
 500        }
 501
 502        return spi_write_then_read(spi, txbuf, len, val_buf, val_size);
 503}
 504
 505static int zl38_bus_write(void *context, const void *data, size_t count)
 506{
 507        struct spi_device *spi = context;
 508        u8 buf[4 + ZL38_MAX_RAW_XFER];
 509        size_t val_len, len = 0;
 510        const u8 *data8 = data;
 511        u8 offs, page;
 512
 513        if (count > (2 + ZL38_MAX_RAW_XFER) || count < 4)
 514                return -EINVAL;
 515        val_len = count - 2;
 516        offs = data8[1] >> 1;
 517        page = data8[0];
 518
 519        if (page) {
 520                buf[len++] = 0xFE;
 521                buf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
 522                buf[len++] = offs;
 523                buf[len++] = (val_len / 2 - 1) | 0x80;
 524        } else {
 525                buf[len++] = offs | 0x80;
 526                buf[len++] = (val_len / 2 - 1) | 0x80;
 527        }
 528        memcpy(buf + len, data8 + 2, val_len);
 529        len += val_len;
 530
 531        return spi_write(spi, buf, len);
 532}
 533
 534static const struct regmap_bus zl38_regmap_bus = {
 535        .read = zl38_bus_read,
 536        .write = zl38_bus_write,
 537        .max_raw_write = ZL38_MAX_RAW_XFER,
 538        .max_raw_read = ZL38_MAX_RAW_XFER,
 539};
 540
 541static const struct regmap_config zl38_regmap_conf = {
 542        .reg_bits = 16,
 543        .val_bits = 16,
 544        .reg_stride = 2,
 545        .use_single_read = true,
 546        .use_single_write = true,
 547};
 548
 549static int zl38_spi_probe(struct spi_device *spi)
 550{
 551        struct device *dev = &spi->dev;
 552        struct zl38_codec_priv *priv;
 553        struct gpio_desc *reset_gpio;
 554        int err;
 555
 556        /* get the chip to a known state by putting it in reset */
 557        reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 558        if (IS_ERR(reset_gpio))
 559                return PTR_ERR(reset_gpio);
 560        if (reset_gpio) {
 561                /* datasheet: need > 10us for a digital + analog reset */
 562                usleep_range(15, 50);
 563                /* take the chip out of reset */
 564                gpiod_set_value_cansleep(reset_gpio, 0);
 565                /* datasheet: need > 3ms for digital section to become stable */
 566                usleep_range(3000, 10000);
 567        }
 568
 569        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 570        if (!priv)
 571                return -ENOMEM;
 572
 573        priv->dev = dev;
 574        dev_set_drvdata(dev, priv);
 575        priv->regmap = devm_regmap_init(dev, &zl38_regmap_bus, spi,
 576                                        &zl38_regmap_conf);
 577        if (IS_ERR(priv->regmap))
 578                return PTR_ERR(priv->regmap);
 579
 580        err = zl38_load_firmware(dev, priv->regmap);
 581        if (err)
 582                return err;
 583
 584        err = zl38_check_revision(dev, priv->regmap);
 585        if (err)
 586                return err;
 587
 588        priv->gpio_chip = devm_kmemdup(dev, &template_chip,
 589                                       sizeof(template_chip), GFP_KERNEL);
 590        if (!priv->gpio_chip)
 591                return -ENOMEM;
 592#ifdef CONFIG_OF_GPIO
 593        priv->gpio_chip->of_node = dev->of_node;
 594#endif
 595        err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap);
 596        if (err)
 597                return err;
 598
 599        /* setup the cross-point switch for stereo bypass */
 600        err = regmap_multi_reg_write(priv->regmap, cp_config_stereo_bypass,
 601                                     ARRAY_SIZE(cp_config_stereo_bypass));
 602        if (err)
 603                return err;
 604        /* setup for 12MHz crystal connected to the chip */
 605        err = regmap_update_bits(priv->regmap, REG_CLK_CFG, CLK_CFG_SOURCE_XTAL,
 606                                 CLK_CFG_SOURCE_XTAL);
 607        if (err)
 608                return err;
 609
 610        return devm_snd_soc_register_component(dev, &zl38_component_dev,
 611                                               &zl38_dai, 1);
 612}
 613
 614static const struct of_device_id zl38_dt_ids[] = {
 615        { .compatible = "mscc,zl38060", },
 616        { /* sentinel */ }
 617};
 618MODULE_DEVICE_TABLE(of, zl38_dt_ids);
 619
 620static const struct spi_device_id zl38_spi_ids[] = {
 621        { "zl38060", 0 },
 622        { /* sentinel */ }
 623};
 624MODULE_DEVICE_TABLE(spi, zl38_spi_ids);
 625
 626static struct spi_driver zl38060_spi_driver = {
 627        .driver = {
 628                .name = DRV_NAME,
 629                .of_match_table = of_match_ptr(zl38_dt_ids),
 630        },
 631        .probe = zl38_spi_probe,
 632        .id_table = zl38_spi_ids,
 633};
 634module_spi_driver(zl38060_spi_driver);
 635
 636MODULE_DESCRIPTION("ASoC ZL38060 driver");
 637MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
 638MODULE_LICENSE("GPL v2");
 639