Commit 2aa13b9e8096ab7f12c67f3a5b9a38b194a30ce9

Authored by Mark Brown
Committed by Samuel Ortiz
1 parent e5b486841d

mfd: Add WM831x SPI support

Implement support for controlling WM831x and WM832x devices using SPI.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

Showing 3 changed files with 244 additions and 0 deletions Side-by-side Diff

... ... @@ -329,6 +329,17 @@
329 329 for accessing the device, additional drivers must be enabled in
330 330 order to use the functionality of the device.
331 331  
  332 +config MFD_WM831X_SPI
  333 + bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
  334 + select MFD_CORE
  335 + select MFD_WM831X
  336 + depends on SPI_MASTER && GENERIC_HARDIRQS
  337 + help
  338 + Support for the Wolfson Microelecronics WM831x and WM832x PMICs
  339 + when controlled using SPI. This driver provides common support
  340 + for accessing the device, additional drivers must be enabled in
  341 + order to use the functionality of the device.
  342 +
332 343 config MFD_WM8350
333 344 bool
334 345 depends on GENERIC_HARDIRQS
drivers/mfd/Makefile
... ... @@ -25,6 +25,7 @@
25 25 wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
26 26 obj-$(CONFIG_MFD_WM831X) += wm831x.o
27 27 obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o
  28 +obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o
28 29 wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
29 30 wm8350-objs += wm8350-irq.o
30 31 obj-$(CONFIG_MFD_WM8350) += wm8350.o
drivers/mfd/wm831x-spi.c
  1 +/*
  2 + * wm831x-spi.c -- SPI access for Wolfson WM831x PMICs
  3 + *
  4 + * Copyright 2009,2010 Wolfson Microelectronics PLC.
  5 + *
  6 + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify it
  9 + * under the terms of the GNU General Public License as published by the
  10 + * Free Software Foundation; either version 2 of the License, or (at your
  11 + * option) any later version.
  12 + *
  13 + */
  14 +
  15 +#include <linux/kernel.h>
  16 +#include <linux/module.h>
  17 +#include <linux/spi/spi.h>
  18 +
  19 +#include <linux/mfd/wm831x/core.h>
  20 +
  21 +static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
  22 + int bytes, void *dest)
  23 +{
  24 + u16 tx_val;
  25 + u16 *d = dest;
  26 + int r, ret;
  27 +
  28 + /* Go register at a time */
  29 + for (r = reg; r < reg + (bytes / 2); r++) {
  30 + tx_val = r | 0x8000;
  31 +
  32 + ret = spi_write_then_read(wm831x->control_data,
  33 + (u8 *)&tx_val, 2, (u8 *)d, 2);
  34 + if (ret != 0)
  35 + return ret;
  36 +
  37 + *d = be16_to_cpu(*d);
  38 +
  39 + d++;
  40 + }
  41 +
  42 + return 0;
  43 +}
  44 +
  45 +static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
  46 + int bytes, void *src)
  47 +{
  48 + struct spi_device *spi = wm831x->control_data;
  49 + u16 *s = src;
  50 + u16 data[2];
  51 + int ret, r;
  52 +
  53 + /* Go register at a time */
  54 + for (r = reg; r < reg + (bytes / 2); r++) {
  55 + data[0] = r;
  56 + data[1] = *s++;
  57 +
  58 + ret = spi_write(spi, (char *)&data, sizeof(data));
  59 + if (ret != 0)
  60 + return ret;
  61 + }
  62 +
  63 + return 0;
  64 +}
  65 +
  66 +static int __devinit wm831x_spi_probe(struct spi_device *spi)
  67 +{
  68 + struct wm831x *wm831x;
  69 + enum wm831x_parent type;
  70 +
  71 + /* Currently SPI support for ID tables is unmerged, we're faking it */
  72 + if (strcmp(spi->modalias, "wm8310") == 0)
  73 + type = WM8310;
  74 + else if (strcmp(spi->modalias, "wm8311") == 0)
  75 + type = WM8311;
  76 + else if (strcmp(spi->modalias, "wm8312") == 0)
  77 + type = WM8312;
  78 + else if (strcmp(spi->modalias, "wm8320") == 0)
  79 + type = WM8320;
  80 + else if (strcmp(spi->modalias, "wm8321") == 0)
  81 + type = WM8321;
  82 + else if (strcmp(spi->modalias, "wm8325") == 0)
  83 + type = WM8325;
  84 + else {
  85 + dev_err(&spi->dev, "Unknown device type\n");
  86 + return -EINVAL;
  87 + }
  88 +
  89 + wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
  90 + if (wm831x == NULL)
  91 + return -ENOMEM;
  92 +
  93 + spi->bits_per_word = 16;
  94 + spi->mode = SPI_MODE_0;
  95 +
  96 + dev_set_drvdata(&spi->dev, wm831x);
  97 + wm831x->dev = &spi->dev;
  98 + wm831x->control_data = spi;
  99 + wm831x->read_dev = wm831x_spi_read_device;
  100 + wm831x->write_dev = wm831x_spi_write_device;
  101 +
  102 + return wm831x_device_init(wm831x, type, spi->irq);
  103 +}
  104 +
  105 +static int __devexit wm831x_spi_remove(struct spi_device *spi)
  106 +{
  107 + struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
  108 +
  109 + wm831x_device_exit(wm831x);
  110 +
  111 + return 0;
  112 +}
  113 +
  114 +static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m)
  115 +{
  116 + struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
  117 +
  118 + return wm831x_device_suspend(wm831x);
  119 +}
  120 +
  121 +static struct spi_driver wm8310_spi_driver = {
  122 + .driver = {
  123 + .name = "wm8310",
  124 + .bus = &spi_bus_type,
  125 + .owner = THIS_MODULE,
  126 + },
  127 + .probe = wm831x_spi_probe,
  128 + .remove = __devexit_p(wm831x_spi_remove),
  129 + .suspend = wm831x_spi_suspend,
  130 +};
  131 +
  132 +static struct spi_driver wm8311_spi_driver = {
  133 + .driver = {
  134 + .name = "wm8311",
  135 + .bus = &spi_bus_type,
  136 + .owner = THIS_MODULE,
  137 + },
  138 + .probe = wm831x_spi_probe,
  139 + .remove = __devexit_p(wm831x_spi_remove),
  140 + .suspend = wm831x_spi_suspend,
  141 +};
  142 +
  143 +static struct spi_driver wm8312_spi_driver = {
  144 + .driver = {
  145 + .name = "wm8312",
  146 + .bus = &spi_bus_type,
  147 + .owner = THIS_MODULE,
  148 + },
  149 + .probe = wm831x_spi_probe,
  150 + .remove = __devexit_p(wm831x_spi_remove),
  151 + .suspend = wm831x_spi_suspend,
  152 +};
  153 +
  154 +static struct spi_driver wm8320_spi_driver = {
  155 + .driver = {
  156 + .name = "wm8320",
  157 + .bus = &spi_bus_type,
  158 + .owner = THIS_MODULE,
  159 + },
  160 + .probe = wm831x_spi_probe,
  161 + .remove = __devexit_p(wm831x_spi_remove),
  162 + .suspend = wm831x_spi_suspend,
  163 +};
  164 +
  165 +static struct spi_driver wm8321_spi_driver = {
  166 + .driver = {
  167 + .name = "wm8321",
  168 + .bus = &spi_bus_type,
  169 + .owner = THIS_MODULE,
  170 + },
  171 + .probe = wm831x_spi_probe,
  172 + .remove = __devexit_p(wm831x_spi_remove),
  173 + .suspend = wm831x_spi_suspend,
  174 +};
  175 +
  176 +static struct spi_driver wm8325_spi_driver = {
  177 + .driver = {
  178 + .name = "wm8325",
  179 + .bus = &spi_bus_type,
  180 + .owner = THIS_MODULE,
  181 + },
  182 + .probe = wm831x_spi_probe,
  183 + .remove = __devexit_p(wm831x_spi_remove),
  184 + .suspend = wm831x_spi_suspend,
  185 +};
  186 +
  187 +static int __init wm831x_spi_init(void)
  188 +{
  189 + int ret;
  190 +
  191 + ret = spi_register_driver(&wm8310_spi_driver);
  192 + if (ret != 0)
  193 + pr_err("Failed to register WM8310 SPI driver: %d\n", ret);
  194 +
  195 + ret = spi_register_driver(&wm8311_spi_driver);
  196 + if (ret != 0)
  197 + pr_err("Failed to register WM8311 SPI driver: %d\n", ret);
  198 +
  199 + ret = spi_register_driver(&wm8312_spi_driver);
  200 + if (ret != 0)
  201 + pr_err("Failed to register WM8312 SPI driver: %d\n", ret);
  202 +
  203 + ret = spi_register_driver(&wm8320_spi_driver);
  204 + if (ret != 0)
  205 + pr_err("Failed to register WM8320 SPI driver: %d\n", ret);
  206 +
  207 + ret = spi_register_driver(&wm8321_spi_driver);
  208 + if (ret != 0)
  209 + pr_err("Failed to register WM8321 SPI driver: %d\n", ret);
  210 +
  211 + ret = spi_register_driver(&wm8325_spi_driver);
  212 + if (ret != 0)
  213 + pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
  214 +
  215 + return 0;
  216 +}
  217 +subsys_initcall(wm831x_spi_init);
  218 +
  219 +static void __exit wm831x_spi_exit(void)
  220 +{
  221 + spi_unregister_driver(&wm8325_spi_driver);
  222 + spi_unregister_driver(&wm8321_spi_driver);
  223 + spi_unregister_driver(&wm8320_spi_driver);
  224 + spi_unregister_driver(&wm8312_spi_driver);
  225 + spi_unregister_driver(&wm8311_spi_driver);
  226 + spi_unregister_driver(&wm8310_spi_driver);
  227 +}
  228 +module_exit(wm831x_spi_exit);
  229 +
  230 +MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs");
  231 +MODULE_LICENSE("GPL");
  232 +MODULE_AUTHOR("Mark Brown");