Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: ssm2602: Split SPI and I2C code into different modules

There are a few known (minor) problems with having the support code for both I2C
and SPI in the same module:
* We need to be extra careful to make sure to not build the driver into the
kernel if one of the subsystems is build as a module (Currently only I2C
can be build as a module).
* The module init path error handling is rather ugly. E.g. what should be
done if either the SPI or the I2C driver fails to register? Most drivers
that implement SPI and I2C in the same module currently fallback to
undefined behavior in that case. Splitting the the driver into two
modules, one for each bus allows the registration of the other bus driver
to continue without problems if one of them fails.

This patch splits the ssm2602 driver into 3 modules. One core module that
implements the device logic, but is independent of the bus method used. And one
module for SPI and I2C each that registers the drivers and sets up the regmap
struct for the bus.

While we are at it also cleanup the include section of the ssm2602 driver and
remove unneeded includes.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Lars-Peter Clausen and committed by
Mark Brown
c924dc68 f75ac2d9

+148 -140
+2 -1
sound/soc/blackfin/Kconfig
··· 14 14 depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) 15 15 select SND_BF5XX_SOC_I2S if !BF60x 16 16 select SND_BF6XX_SOC_I2S if BF60x 17 - select SND_SOC_SSM2602 17 + select SND_SOC_SSM2602_SPI if SPI_MASTER 18 + select SND_SOC_SSM2602_I2C if I2C 18 19 help 19 20 Say Y if you want to add support for the Analog Devices 20 21 SSM2602 Audio Codec Add-On Card.
+10 -1
sound/soc/codecs/Kconfig
··· 66 66 select SND_SOC_SN95031 if INTEL_SCU_IPC 67 67 select SND_SOC_SPDIF 68 68 select SND_SOC_SSM2518 if I2C 69 - select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI 69 + select SND_SOC_SSM2602_SPI if SPI_MASTER 70 + select SND_SOC_SSM2602_I2C if I2C 70 71 select SND_SOC_STA32X if I2C 71 72 select SND_SOC_STA529 if I2C 72 73 select SND_SOC_STAC9766 if SND_SOC_AC97_BUS ··· 341 340 tristate 342 341 343 342 config SND_SOC_SSM2602 343 + tristate 344 + 345 + config SND_SOC_SSM2602_SPI 346 + select SND_SOC_SSM2602 347 + tristate 348 + 349 + config SND_SOC_SSM2602_I2C 350 + select SND_SOC_SSM2602 344 351 tristate 345 352 346 353 config SND_SOC_STA32X
+4
sound/soc/codecs/Makefile
··· 58 58 snd-soc-spdif-rx-objs := spdif_receiver.o 59 59 snd-soc-ssm2518-objs := ssm2518.o 60 60 snd-soc-ssm2602-objs := ssm2602.o 61 + snd-soc-ssm2602-spi-objs := ssm2602-spi.o 62 + snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o 61 63 snd-soc-sta32x-objs := sta32x.o 62 64 snd-soc-sta529-objs := sta529.o 63 65 snd-soc-stac9766-objs := stac9766.o ··· 190 188 obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o 191 189 obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o 192 190 obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o 191 + obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o 192 + obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o 193 193 obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o 194 194 obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o 195 195 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
+57
sound/soc/codecs/ssm2602-i2c.c
··· 1 + /* 2 + * SSM2602/SSM2603/SSM2604 I2C audio driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * 6 + * Licensed under the GPL-2. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/i2c.h> 11 + #include <linux/regmap.h> 12 + 13 + #include <sound/soc.h> 14 + 15 + #include "ssm2602.h" 16 + 17 + /* 18 + * ssm2602 2 wire address is determined by GPIO5 19 + * state during powerup. 20 + * low = 0x1a 21 + * high = 0x1b 22 + */ 23 + static int ssm2602_i2c_probe(struct i2c_client *client, 24 + const struct i2c_device_id *id) 25 + { 26 + return ssm2602_probe(&client->dev, id->driver_data, 27 + devm_regmap_init_i2c(client, &ssm2602_regmap_config)); 28 + } 29 + 30 + static int ssm2602_i2c_remove(struct i2c_client *client) 31 + { 32 + snd_soc_unregister_codec(&client->dev); 33 + return 0; 34 + } 35 + 36 + static const struct i2c_device_id ssm2602_i2c_id[] = { 37 + { "ssm2602", SSM2602 }, 38 + { "ssm2603", SSM2602 }, 39 + { "ssm2604", SSM2604 }, 40 + { } 41 + }; 42 + MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); 43 + 44 + static struct i2c_driver ssm2602_i2c_driver = { 45 + .driver = { 46 + .name = "ssm2602", 47 + .owner = THIS_MODULE, 48 + }, 49 + .probe = ssm2602_i2c_probe, 50 + .remove = ssm2602_i2c_remove, 51 + .id_table = ssm2602_i2c_id, 52 + }; 53 + module_i2c_driver(ssm2602_i2c_driver); 54 + 55 + MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver"); 56 + MODULE_AUTHOR("Cliff Cai"); 57 + MODULE_LICENSE("GPL");
+41
sound/soc/codecs/ssm2602-spi.c
··· 1 + /* 2 + * SSM2602 SPI audio driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * 6 + * Licensed under the GPL-2. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/spi/spi.h> 11 + #include <linux/regmap.h> 12 + 13 + #include <sound/soc.h> 14 + 15 + #include "ssm2602.h" 16 + 17 + static int ssm2602_spi_probe(struct spi_device *spi) 18 + { 19 + return ssm2602_probe(&spi->dev, SSM2602, 20 + devm_regmap_init_spi(spi, &ssm2602_regmap_config)); 21 + } 22 + 23 + static int ssm2602_spi_remove(struct spi_device *spi) 24 + { 25 + snd_soc_unregister_codec(&spi->dev); 26 + return 0; 27 + } 28 + 29 + static struct spi_driver ssm2602_spi_driver = { 30 + .driver = { 31 + .name = "ssm2602", 32 + .owner = THIS_MODULE, 33 + }, 34 + .probe = ssm2602_spi_probe, 35 + .remove = ssm2602_spi_remove, 36 + }; 37 + module_spi_driver(ssm2602_spi_driver); 38 + 39 + MODULE_DESCRIPTION("ASoC SSM2602 SPI driver"); 40 + MODULE_AUTHOR("Cliff Cai"); 41 + MODULE_LICENSE("GPL");
+20 -138
sound/soc/codecs/ssm2602.c
··· 27 27 */ 28 28 29 29 #include <linux/module.h> 30 - #include <linux/moduleparam.h> 31 - #include <linux/init.h> 32 - #include <linux/delay.h> 33 - #include <linux/pm.h> 34 - #include <linux/i2c.h> 35 - #include <linux/spi/spi.h> 36 30 #include <linux/regmap.h> 37 31 #include <linux/slab.h> 38 - #include <sound/core.h> 32 + 39 33 #include <sound/pcm.h> 40 34 #include <sound/pcm_params.h> 41 35 #include <sound/soc.h> 42 - #include <sound/initval.h> 43 36 #include <sound/tlv.h> 44 37 45 38 #include "ssm2602.h" 46 - 47 - enum ssm2602_type { 48 - SSM2602, 49 - SSM2604, 50 - }; 51 39 52 40 /* codec private data */ 53 41 struct ssm2602_priv { ··· 517 529 return 0; 518 530 } 519 531 520 - static int ssm2602_probe(struct snd_soc_codec *codec) 532 + static int ssm2602_codec_probe(struct snd_soc_codec *codec) 521 533 { 522 534 struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); 523 535 struct snd_soc_dapm_context *dapm = &codec->dapm; ··· 542 554 ARRAY_SIZE(ssm2602_routes)); 543 555 } 544 556 545 - static int ssm2604_probe(struct snd_soc_codec *codec) 557 + static int ssm2604_codec_probe(struct snd_soc_codec *codec) 546 558 { 547 559 struct snd_soc_dapm_context *dapm = &codec->dapm; 548 560 int ret; ··· 556 568 ARRAY_SIZE(ssm2604_routes)); 557 569 } 558 570 559 - static int ssm260x_probe(struct snd_soc_codec *codec) 571 + static int ssm260x_codec_probe(struct snd_soc_codec *codec) 560 572 { 561 573 struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); 562 574 int ret; ··· 585 597 586 598 switch (ssm2602->type) { 587 599 case SSM2602: 588 - ret = ssm2602_probe(codec); 600 + ret = ssm2602_codec_probe(codec); 589 601 break; 590 602 case SSM2604: 591 - ret = ssm2604_probe(codec); 603 + ret = ssm2604_codec_probe(codec); 592 604 break; 593 605 } 594 606 ··· 608 620 } 609 621 610 622 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { 611 - .probe = ssm260x_probe, 623 + .probe = ssm260x_codec_probe, 612 624 .remove = ssm2602_remove, 613 625 .suspend = ssm2602_suspend, 614 626 .resume = ssm2602_resume, ··· 627 639 return reg == SSM2602_RESET; 628 640 } 629 641 630 - static const struct regmap_config ssm2602_regmap_config = { 642 + const struct regmap_config ssm2602_regmap_config = { 631 643 .val_bits = 9, 632 644 .reg_bits = 7, 633 645 ··· 638 650 .reg_defaults_raw = ssm2602_reg, 639 651 .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), 640 652 }; 653 + EXPORT_SYMBOL_GPL(ssm2602_regmap_config); 641 654 642 - #if defined(CONFIG_SPI_MASTER) 643 - static int ssm2602_spi_probe(struct spi_device *spi) 655 + int ssm2602_probe(struct device *dev, enum ssm2602_type type, 656 + struct regmap *regmap) 644 657 { 645 658 struct ssm2602_priv *ssm2602; 646 - int ret; 647 659 648 - ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv), 649 - GFP_KERNEL); 660 + if (IS_ERR(regmap)) 661 + return PTR_ERR(regmap); 662 + 663 + ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL); 650 664 if (ssm2602 == NULL) 651 665 return -ENOMEM; 652 666 653 - spi_set_drvdata(spi, ssm2602); 667 + dev_set_drvdata(dev, ssm2602); 654 668 ssm2602->type = SSM2602; 669 + ssm2602->regmap = regmap; 655 670 656 - ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config); 657 - if (IS_ERR(ssm2602->regmap)) 658 - return PTR_ERR(ssm2602->regmap); 659 - 660 - ret = snd_soc_register_codec(&spi->dev, 661 - &soc_codec_dev_ssm2602, &ssm2602_dai, 1); 662 - return ret; 671 + return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, 672 + &ssm2602_dai, 1); 663 673 } 664 - 665 - static int ssm2602_spi_remove(struct spi_device *spi) 666 - { 667 - snd_soc_unregister_codec(&spi->dev); 668 - return 0; 669 - } 670 - 671 - static struct spi_driver ssm2602_spi_driver = { 672 - .driver = { 673 - .name = "ssm2602", 674 - .owner = THIS_MODULE, 675 - }, 676 - .probe = ssm2602_spi_probe, 677 - .remove = ssm2602_spi_remove, 678 - }; 679 - #endif 680 - 681 - #if IS_ENABLED(CONFIG_I2C) 682 - /* 683 - * ssm2602 2 wire address is determined by GPIO5 684 - * state during powerup. 685 - * low = 0x1a 686 - * high = 0x1b 687 - */ 688 - static int ssm2602_i2c_probe(struct i2c_client *i2c, 689 - const struct i2c_device_id *id) 690 - { 691 - struct ssm2602_priv *ssm2602; 692 - int ret; 693 - 694 - ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv), 695 - GFP_KERNEL); 696 - if (ssm2602 == NULL) 697 - return -ENOMEM; 698 - 699 - i2c_set_clientdata(i2c, ssm2602); 700 - ssm2602->type = id->driver_data; 701 - 702 - ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config); 703 - if (IS_ERR(ssm2602->regmap)) 704 - return PTR_ERR(ssm2602->regmap); 705 - 706 - ret = snd_soc_register_codec(&i2c->dev, 707 - &soc_codec_dev_ssm2602, &ssm2602_dai, 1); 708 - return ret; 709 - } 710 - 711 - static int ssm2602_i2c_remove(struct i2c_client *client) 712 - { 713 - snd_soc_unregister_codec(&client->dev); 714 - return 0; 715 - } 716 - 717 - static const struct i2c_device_id ssm2602_i2c_id[] = { 718 - { "ssm2602", SSM2602 }, 719 - { "ssm2603", SSM2602 }, 720 - { "ssm2604", SSM2604 }, 721 - { } 722 - }; 723 - MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); 724 - 725 - /* corgi i2c codec control layer */ 726 - static struct i2c_driver ssm2602_i2c_driver = { 727 - .driver = { 728 - .name = "ssm2602", 729 - .owner = THIS_MODULE, 730 - }, 731 - .probe = ssm2602_i2c_probe, 732 - .remove = ssm2602_i2c_remove, 733 - .id_table = ssm2602_i2c_id, 734 - }; 735 - #endif 736 - 737 - 738 - static int __init ssm2602_modinit(void) 739 - { 740 - int ret = 0; 741 - 742 - #if defined(CONFIG_SPI_MASTER) 743 - ret = spi_register_driver(&ssm2602_spi_driver); 744 - if (ret) 745 - return ret; 746 - #endif 747 - 748 - #if IS_ENABLED(CONFIG_I2C) 749 - ret = i2c_add_driver(&ssm2602_i2c_driver); 750 - if (ret) 751 - return ret; 752 - #endif 753 - 754 - return ret; 755 - } 756 - module_init(ssm2602_modinit); 757 - 758 - static void __exit ssm2602_exit(void) 759 - { 760 - #if defined(CONFIG_SPI_MASTER) 761 - spi_unregister_driver(&ssm2602_spi_driver); 762 - #endif 763 - 764 - #if IS_ENABLED(CONFIG_I2C) 765 - i2c_del_driver(&ssm2602_i2c_driver); 766 - #endif 767 - } 768 - module_exit(ssm2602_exit); 674 + EXPORT_SYMBOL_GPL(ssm2602_probe); 769 675 770 676 MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); 771 677 MODULE_AUTHOR("Cliff Cai");
+14
sound/soc/codecs/ssm2602.h
··· 28 28 #ifndef _SSM2602_H 29 29 #define _SSM2602_H 30 30 31 + #include <linux/regmap.h> 32 + 33 + struct device; 34 + 35 + enum ssm2602_type { 36 + SSM2602, 37 + SSM2604, 38 + }; 39 + 40 + extern const struct regmap_config ssm2602_regmap_config; 41 + 42 + int ssm2602_probe(struct device *dev, enum ssm2602_type type, 43 + struct regmap *regmap); 44 + 31 45 /* SSM2602 Codec Register definitions */ 32 46 33 47 #define SSM2602_LINVOL 0x00