zl38060.c 16 KB

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