~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/zl38060.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 84 struct 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 
 91 static 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 
113 static 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 
124 static 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 
138 static int
139 zl38_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 
151 static 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 
162 static 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 
204 out:
205         release_firmware(fw);
206         return err;
207 }
208 
209 
210 static 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 
232 static 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_CLOCK_PROVIDER_MASK) {
254         case SND_SOC_DAIFMT_CBP_CFP:
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 
269 static 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 
310 skip_setup:
311         priv->is_stream_in_use[tx] = true;
312 
313         return 0;
314 }
315 
316 static 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 */
328 static 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 
340 static 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 
346 static 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 
368 static 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 
375 static const struct snd_soc_dapm_route zl38_dapm_routes[] = {
376         { "DAC1",  NULL, "Playback" },
377         { "DAC2",  NULL, "Playback" },
378 
379         { "Capture",  NULL, "DMICL" },
380 };
381 
382 static 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 };
389 
390 static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
391 {
392         struct regmap *regmap = gpiochip_get_data(c);
393         unsigned int mask = BIT(offset);
394 
395         regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
396 }
397 
398 static int chip_gpio_get(struct gpio_chip *c, unsigned int offset)
399 {
400         struct regmap *regmap = gpiochip_get_data(c);
401         unsigned int mask = BIT(offset);
402         unsigned int val;
403         int err;
404 
405         err = regmap_read(regmap, REG_GPIO_DAT, &val);
406         if (err)
407                 return err;
408 
409         return !!(val & mask);
410 }
411 
412 static int chip_direction_input(struct gpio_chip *c, unsigned int offset)
413 {
414         struct regmap *regmap = gpiochip_get_data(c);
415         unsigned int mask = BIT(offset);
416 
417         return regmap_update_bits(regmap, REG_GPIO_DIR, mask, 0);
418 }
419 
420 static int
421 chip_direction_output(struct gpio_chip *c, unsigned int offset, int val)
422 {
423         struct regmap *regmap = gpiochip_get_data(c);
424         unsigned int mask = BIT(offset);
425 
426         chip_gpio_set(c, offset, val);
427         return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask);
428 }
429 
430 static const struct gpio_chip template_chip = {
431         .owner = THIS_MODULE,
432         .label = DRV_NAME,
433 
434         .base = -1,
435         .ngpio = 14,
436         .direction_input = chip_direction_input,
437         .direction_output = chip_direction_output,
438         .get = chip_gpio_get,
439         .set = chip_gpio_set,
440 
441         .can_sleep = true,
442 };
443 
444 static int zl38_check_revision(struct device *dev, struct regmap *regmap)
445 {
446         unsigned int hwrev, fwprod, fwrev;
447         int fw_major, fw_minor, fw_micro;
448         int err;
449 
450         err = regmap_read(regmap, REG_HW_REV, &hwrev);
451         if (err)
452                 return err;
453         err = regmap_read(regmap, REG_FW_PROD, &fwprod);
454         if (err)
455                 return err;
456         err = regmap_read(regmap, REG_FW_REV, &fwrev);
457         if (err)
458                 return err;
459 
460         fw_major = (fwrev >> 12) & 0xF;
461         fw_minor = (fwrev >>  8) & 0xF;
462         fw_micro = fwrev & 0xFF;
463         dev_info(dev, "hw rev 0x%x, fw product code %d, firmware rev %d.%d.%d",
464                  hwrev & 0x1F, fwprod, fw_major, fw_minor, fw_micro);
465 
466         if (fw_major != FIRMWARE_MAJOR || fw_minor < FIRMWARE_MINOR) {
467                 dev_err(dev, "unsupported firmware. driver supports %d.%d",
468                         FIRMWARE_MAJOR, FIRMWARE_MINOR);
469                 return -EINVAL;
470         }
471 
472         return 0;
473 }
474 
475 static int zl38_bus_read(void *context,
476                          const void *reg_buf, size_t reg_size,
477                          void *val_buf, size_t val_size)
478 {
479         struct spi_device *spi = context;
480         const u8 *reg_buf8 = reg_buf;
481         size_t len = 0;
482         u8 offs, page;
483         u8 txbuf[4];
484 
485         if (reg_size != 2 || val_size > ZL38_MAX_RAW_XFER)
486                 return -EINVAL;
487 
488         offs = reg_buf8[1] >> 1;
489         page = reg_buf8[0];
490 
491         if (page) {
492                 txbuf[len++] = 0xFE;
493                 txbuf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
494                 txbuf[len++] = offs;
495                 txbuf[len++] = val_size / 2 - 1;
496         } else {
497                 txbuf[len++] = offs | 0x80;
498                 txbuf[len++] = val_size / 2 - 1;
499         }
500 
501         return spi_write_then_read(spi, txbuf, len, val_buf, val_size);
502 }
503 
504 static int zl38_bus_write(void *context, const void *data, size_t count)
505 {
506         struct spi_device *spi = context;
507         u8 buf[4 + ZL38_MAX_RAW_XFER];
508         size_t val_len, len = 0;
509         const u8 *data8 = data;
510         u8 offs, page;
511 
512         if (count > (2 + ZL38_MAX_RAW_XFER) || count < 4)
513                 return -EINVAL;
514         val_len = count - 2;
515         offs = data8[1] >> 1;
516         page = data8[0];
517 
518         if (page) {
519                 buf[len++] = 0xFE;
520                 buf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
521                 buf[len++] = offs;
522                 buf[len++] = (val_len / 2 - 1) | 0x80;
523         } else {
524                 buf[len++] = offs | 0x80;
525                 buf[len++] = (val_len / 2 - 1) | 0x80;
526         }
527         memcpy(buf + len, data8 + 2, val_len);
528         len += val_len;
529 
530         return spi_write(spi, buf, len);
531 }
532 
533 static const struct regmap_bus zl38_regmap_bus = {
534         .read = zl38_bus_read,
535         .write = zl38_bus_write,
536         .max_raw_write = ZL38_MAX_RAW_XFER,
537         .max_raw_read = ZL38_MAX_RAW_XFER,
538 };
539 
540 static const struct regmap_config zl38_regmap_conf = {
541         .reg_bits = 16,
542         .val_bits = 16,
543         .reg_stride = 2,
544         .use_single_read = true,
545         .use_single_write = true,
546 };
547 
548 static int zl38_spi_probe(struct spi_device *spi)
549 {
550         struct device *dev = &spi->dev;
551         struct zl38_codec_priv *priv;
552         struct gpio_desc *reset_gpio;
553         int err;
554 
555         /* get the chip to a known state by putting it in reset */
556         reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
557         if (IS_ERR(reset_gpio))
558                 return PTR_ERR(reset_gpio);
559         if (reset_gpio) {
560                 /* datasheet: need > 10us for a digital + analog reset */
561                 usleep_range(15, 50);
562                 /* take the chip out of reset */
563                 gpiod_set_value_cansleep(reset_gpio, 0);
564                 /* datasheet: need > 3ms for digital section to become stable */
565                 usleep_range(3000, 10000);
566         }
567 
568         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
569         if (!priv)
570                 return -ENOMEM;
571 
572         priv->dev = dev;
573         dev_set_drvdata(dev, priv);
574         priv->regmap = devm_regmap_init(dev, &zl38_regmap_bus, spi,
575                                         &zl38_regmap_conf);
576         if (IS_ERR(priv->regmap))
577                 return PTR_ERR(priv->regmap);
578 
579         err = zl38_load_firmware(dev, priv->regmap);
580         if (err)
581                 return err;
582 
583         err = zl38_check_revision(dev, priv->regmap);
584         if (err)
585                 return err;
586 
587         priv->gpio_chip = devm_kmemdup(dev, &template_chip,
588                                        sizeof(template_chip), GFP_KERNEL);
589         if (!priv->gpio_chip)
590                 return -ENOMEM;
591         priv->gpio_chip->parent = dev;
592         err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap);
593         if (err)
594                 return err;
595 
596         /* setup the cross-point switch for stereo bypass */
597         err = regmap_multi_reg_write(priv->regmap, cp_config_stereo_bypass,
598                                      ARRAY_SIZE(cp_config_stereo_bypass));
599         if (err)
600                 return err;
601         /* setup for 12MHz crystal connected to the chip */
602         err = regmap_update_bits(priv->regmap, REG_CLK_CFG, CLK_CFG_SOURCE_XTAL,
603                                  CLK_CFG_SOURCE_XTAL);
604         if (err)
605                 return err;
606 
607         return devm_snd_soc_register_component(dev, &zl38_component_dev,
608                                                &zl38_dai, 1);
609 }
610 
611 static const struct of_device_id zl38_dt_ids[] __maybe_unused = {
612         { .compatible = "mscc,zl38060", },
613         { /* sentinel */ }
614 };
615 MODULE_DEVICE_TABLE(of, zl38_dt_ids);
616 
617 static const struct spi_device_id zl38_spi_ids[] = {
618         { "zl38060", 0 },
619         { /* sentinel */ }
620 };
621 MODULE_DEVICE_TABLE(spi, zl38_spi_ids);
622 
623 static struct spi_driver zl38060_spi_driver = {
624         .driver = {
625                 .name = DRV_NAME,
626                 .of_match_table = of_match_ptr(zl38_dt_ids),
627         },
628         .probe = zl38_spi_probe,
629         .id_table = zl38_spi_ids,
630 };
631 module_spi_driver(zl38060_spi_driver);
632 
633 MODULE_DESCRIPTION("ASoC ZL38060 driver");
634 MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
635 MODULE_LICENSE("GPL v2");
636 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php