linux/drivers/mfd/mc13xxx-spi.c
<<
>>
Prefs
   1/*
   2 * Copyright 2009-2010 Pengutronix
   3 * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
   4 *
   5 * loosely based on an earlier driver that has
   6 * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it under
   9 * the terms of the GNU General Public License version 2 as published by the
  10 * Free Software Foundation.
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/mutex.h>
  17#include <linux/interrupt.h>
  18#include <linux/mfd/core.h>
  19#include <linux/mfd/mc13xxx.h>
  20#include <linux/of.h>
  21#include <linux/of_device.h>
  22#include <linux/of_gpio.h>
  23#include <linux/err.h>
  24#include <linux/spi/spi.h>
  25
  26#include "mc13xxx.h"
  27
  28static const struct spi_device_id mc13xxx_device_id[] = {
  29        {
  30                .name = "mc13783",
  31                .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc13783,
  32        }, {
  33                .name = "mc13892",
  34                .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc13892,
  35        }, {
  36                .name = "mc34708",
  37                .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc34708,
  38        }, {
  39                /* sentinel */
  40        }
  41};
  42MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
  43
  44static const struct of_device_id mc13xxx_dt_ids[] = {
  45        { .compatible = "fsl,mc13783", .data = &mc13xxx_variant_mc13783, },
  46        { .compatible = "fsl,mc13892", .data = &mc13xxx_variant_mc13892, },
  47        { .compatible = "fsl,mc34708", .data = &mc13xxx_variant_mc34708, },
  48        { /* sentinel */ }
  49};
  50MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
  51
  52static struct regmap_config mc13xxx_regmap_spi_config = {
  53        .reg_bits = 7,
  54        .pad_bits = 1,
  55        .val_bits = 24,
  56        .write_flag_mask = 0x80,
  57
  58        .max_register = MC13XXX_NUMREGS,
  59
  60        .cache_type = REGCACHE_NONE,
  61        .use_single_rw = 1,
  62};
  63
  64static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size,
  65                                void *val, size_t val_size)
  66{
  67        unsigned char w[4] = { *((unsigned char *) reg), 0, 0, 0};
  68        unsigned char r[4];
  69        unsigned char *p = val;
  70        struct device *dev = context;
  71        struct spi_device *spi = to_spi_device(dev);
  72        struct spi_transfer t = {
  73                .tx_buf = w,
  74                .rx_buf = r,
  75                .len = 4,
  76        };
  77
  78        struct spi_message m;
  79        int ret;
  80
  81        if (val_size != 3 || reg_size != 1)
  82                return -ENOTSUPP;
  83
  84        spi_message_init(&m);
  85        spi_message_add_tail(&t, &m);
  86        ret = spi_sync(spi, &m);
  87
  88        memcpy(p, &r[1], 3);
  89
  90        return ret;
  91}
  92
  93static int mc13xxx_spi_write(void *context, const void *data, size_t count)
  94{
  95        struct device *dev = context;
  96        struct spi_device *spi = to_spi_device(dev);
  97
  98        if (count != 4)
  99                return -ENOTSUPP;
 100
 101        return spi_write(spi, data, count);
 102}
 103
 104/*
 105 * We cannot use regmap-spi generic bus implementation here.
 106 * The MC13783 chip will get corrupted if CS signal is deasserted
 107 * and on i.Mx31 SoC (the target SoC for MC13783 PMIC) the SPI controller
 108 * has the following errata (DSPhl22960):
 109 * "The CSPI negates SS when the FIFO becomes empty with
 110 * SSCTL= 0. Software cannot guarantee that the FIFO will not
 111 * drain because of higher priority interrupts and the
 112 * non-realtime characteristics of the operating system. As a
 113 * result, the SS will negate before all of the data has been
 114 * transferred to/from the peripheral."
 115 * We workaround this by accessing the SPI controller with a
 116 * single transfert.
 117 */
 118
 119static struct regmap_bus regmap_mc13xxx_bus = {
 120        .write = mc13xxx_spi_write,
 121        .read = mc13xxx_spi_read,
 122};
 123
 124static int mc13xxx_spi_probe(struct spi_device *spi)
 125{
 126        struct mc13xxx *mc13xxx;
 127        struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
 128        int ret;
 129
 130        mc13xxx = devm_kzalloc(&spi->dev, sizeof(*mc13xxx), GFP_KERNEL);
 131        if (!mc13xxx)
 132                return -ENOMEM;
 133
 134        spi_set_drvdata(spi, mc13xxx);
 135        spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
 136
 137        mc13xxx->dev = &spi->dev;
 138        mutex_init(&mc13xxx->lock);
 139
 140        mc13xxx->regmap = devm_regmap_init(&spi->dev, &regmap_mc13xxx_bus,
 141                                           &spi->dev,
 142                                           &mc13xxx_regmap_spi_config);
 143        if (IS_ERR(mc13xxx->regmap)) {
 144                ret = PTR_ERR(mc13xxx->regmap);
 145                dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
 146                                ret);
 147                spi_set_drvdata(spi, NULL);
 148                return ret;
 149        }
 150
 151        if (spi->dev.of_node) {
 152                const struct of_device_id *of_id =
 153                        of_match_device(mc13xxx_dt_ids, &spi->dev);
 154
 155                mc13xxx->variant = of_id->data;
 156        } else {
 157                const struct spi_device_id *id_entry = spi_get_device_id(spi);
 158
 159                mc13xxx->variant = (void *)id_entry->driver_data;
 160        }
 161
 162        return mc13xxx_common_init(mc13xxx, pdata, spi->irq);
 163}
 164
 165static int mc13xxx_spi_remove(struct spi_device *spi)
 166{
 167        struct mc13xxx *mc13xxx = spi_get_drvdata(spi);
 168
 169        mc13xxx_common_cleanup(mc13xxx);
 170
 171        return 0;
 172}
 173
 174static struct spi_driver mc13xxx_spi_driver = {
 175        .id_table = mc13xxx_device_id,
 176        .driver = {
 177                .name = "mc13xxx",
 178                .owner = THIS_MODULE,
 179                .of_match_table = mc13xxx_dt_ids,
 180        },
 181        .probe = mc13xxx_spi_probe,
 182        .remove = mc13xxx_spi_remove,
 183};
 184
 185static int __init mc13xxx_init(void)
 186{
 187        return spi_register_driver(&mc13xxx_spi_driver);
 188}
 189subsys_initcall(mc13xxx_init);
 190
 191static void __exit mc13xxx_exit(void)
 192{
 193        spi_unregister_driver(&mc13xxx_spi_driver);
 194}
 195module_exit(mc13xxx_exit);
 196
 197MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
 198MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
 199MODULE_LICENSE("GPL v2");
 200
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.