linux/drivers/mfd/dm355evm_msp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * dm355evm_msp.c - driver for MSP430 firmware on DM355EVM board
   4 *
   5 * Copyright (C) 2008 David Brownell
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/mutex.h>
  10#include <linux/platform_device.h>
  11#include <linux/clk.h>
  12#include <linux/module.h>
  13#include <linux/err.h>
  14#include <linux/gpio.h>
  15#include <linux/leds.h>
  16#include <linux/i2c.h>
  17#include <linux/mfd/dm355evm_msp.h>
  18
  19
  20/*
  21 * The DM355 is a DaVinci chip with video support but no C64+ DSP.  Its
  22 * EVM board has an MSP430 programmed with firmware for various board
  23 * support functions.  This driver exposes some of them directly, and
  24 * supports other drivers (e.g. RTC, input) for more complex access.
  25 *
  26 * Because this firmware is entirely board-specific, this file embeds
  27 * knowledge that would be passed as platform_data in a generic driver.
  28 *
  29 * This driver was tested with firmware revision A4.
  30 */
  31
  32#if IS_ENABLED(CONFIG_INPUT_DM355EVM)
  33#define msp_has_keyboard()      true
  34#else
  35#define msp_has_keyboard()      false
  36#endif
  37
  38#if IS_ENABLED(CONFIG_LEDS_GPIO)
  39#define msp_has_leds()          true
  40#else
  41#define msp_has_leds()          false
  42#endif
  43
  44#if IS_ENABLED(CONFIG_RTC_DRV_DM355EVM)
  45#define msp_has_rtc()           true
  46#else
  47#define msp_has_rtc()           false
  48#endif
  49
  50#if IS_ENABLED(CONFIG_VIDEO_TVP514X)
  51#define msp_has_tvp()           true
  52#else
  53#define msp_has_tvp()           false
  54#endif
  55
  56
  57/*----------------------------------------------------------------------*/
  58
  59/* REVISIT for paranoia's sake, retry reads/writes on error */
  60
  61static struct i2c_client *msp430;
  62
  63/**
  64 * dm355evm_msp_write - Writes a register in dm355evm_msp
  65 * @value: the value to be written
  66 * @reg: register address
  67 *
  68 * Returns result of operation - 0 is success, else negative errno
  69 */
  70int dm355evm_msp_write(u8 value, u8 reg)
  71{
  72        return i2c_smbus_write_byte_data(msp430, reg, value);
  73}
  74EXPORT_SYMBOL(dm355evm_msp_write);
  75
  76/**
  77 * dm355evm_msp_read - Reads a register from dm355evm_msp
  78 * @reg: register address
  79 *
  80 * Returns result of operation - value, or negative errno
  81 */
  82int dm355evm_msp_read(u8 reg)
  83{
  84        return i2c_smbus_read_byte_data(msp430, reg);
  85}
  86EXPORT_SYMBOL(dm355evm_msp_read);
  87
  88/*----------------------------------------------------------------------*/
  89
  90/*
  91 * Many of the msp430 pins are just used as fixed-direction GPIOs.
  92 * We could export a few more of them this way, if we wanted.
  93 */
  94#define MSP_GPIO(bit, reg)      ((DM355EVM_MSP_ ## reg) << 3 | (bit))
  95
  96static const u8 msp_gpios[] = {
  97        /* eight leds */
  98        MSP_GPIO(0, LED), MSP_GPIO(1, LED),
  99        MSP_GPIO(2, LED), MSP_GPIO(3, LED),
 100        MSP_GPIO(4, LED), MSP_GPIO(5, LED),
 101        MSP_GPIO(6, LED), MSP_GPIO(7, LED),
 102        /* SW6 and the NTSC/nPAL jumper */
 103        MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1),
 104        MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1),
 105        MSP_GPIO(4, SWITCH1),
 106        /* switches on MMC/SD sockets */
 107        /*
 108         * Note: EVMDM355_ECP_VA4.pdf suggests that Bit 2 and 4 should be
 109         * checked for card detection. However on the EVM bit 1 and 3 gives
 110         * this status, for 0 and 1 instance respectively. The pdf also
 111         * suggests that Bit 1 and 3 should be checked for write protection.
 112         * However on the EVM bit 2 and 4 gives this status,for 0 and 1
 113         * instance respectively.
 114         */
 115        MSP_GPIO(2, SDMMC), MSP_GPIO(1, SDMMC), /* mmc0 WP, nCD */
 116        MSP_GPIO(4, SDMMC), MSP_GPIO(3, SDMMC), /* mmc1 WP, nCD */
 117};
 118
 119#define MSP_GPIO_REG(offset)    (msp_gpios[(offset)] >> 3)
 120#define MSP_GPIO_MASK(offset)   BIT(msp_gpios[(offset)] & 0x07)
 121
 122static int msp_gpio_in(struct gpio_chip *chip, unsigned offset)
 123{
 124        switch (MSP_GPIO_REG(offset)) {
 125        case DM355EVM_MSP_SWITCH1:
 126        case DM355EVM_MSP_SWITCH2:
 127        case DM355EVM_MSP_SDMMC:
 128                return 0;
 129        default:
 130                return -EINVAL;
 131        }
 132}
 133
 134static u8 msp_led_cache;
 135
 136static int msp_gpio_get(struct gpio_chip *chip, unsigned offset)
 137{
 138        int reg, status;
 139
 140        reg = MSP_GPIO_REG(offset);
 141        status = dm355evm_msp_read(reg);
 142        if (status < 0)
 143                return status;
 144        if (reg == DM355EVM_MSP_LED)
 145                msp_led_cache = status;
 146        return !!(status & MSP_GPIO_MASK(offset));
 147}
 148
 149static int msp_gpio_out(struct gpio_chip *chip, unsigned offset, int value)
 150{
 151        int mask, bits;
 152
 153        /* NOTE:  there are some other signals that could be
 154         * packaged as output GPIOs, but they aren't as useful
 155         * as the LEDs ... so for now we don't.
 156         */
 157        if (MSP_GPIO_REG(offset) != DM355EVM_MSP_LED)
 158                return -EINVAL;
 159
 160        mask = MSP_GPIO_MASK(offset);
 161        bits = msp_led_cache;
 162
 163        bits &= ~mask;
 164        if (value)
 165                bits |= mask;
 166        msp_led_cache = bits;
 167
 168        return dm355evm_msp_write(bits, DM355EVM_MSP_LED);
 169}
 170
 171static void msp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 172{
 173        msp_gpio_out(chip, offset, value);
 174}
 175
 176static struct gpio_chip dm355evm_msp_gpio = {
 177        .label                  = "dm355evm_msp",
 178        .owner                  = THIS_MODULE,
 179        .direction_input        = msp_gpio_in,
 180        .get                    = msp_gpio_get,
 181        .direction_output       = msp_gpio_out,
 182        .set                    = msp_gpio_set,
 183        .base                   = -EINVAL,              /* dynamic assignment */
 184        .ngpio                  = ARRAY_SIZE(msp_gpios),
 185        .can_sleep              = true,
 186};
 187
 188/*----------------------------------------------------------------------*/
 189
 190static struct device *add_child(struct i2c_client *client, const char *name,
 191                void *pdata, unsigned pdata_len,
 192                bool can_wakeup, int irq)
 193{
 194        struct platform_device  *pdev;
 195        int                     status;
 196
 197        pdev = platform_device_alloc(name, -1);
 198        if (!pdev)
 199                return ERR_PTR(-ENOMEM);
 200
 201        device_init_wakeup(&pdev->dev, can_wakeup);
 202        pdev->dev.parent = &client->dev;
 203
 204        if (pdata) {
 205                status = platform_device_add_data(pdev, pdata, pdata_len);
 206                if (status < 0) {
 207                        dev_dbg(&pdev->dev, "can't add platform_data\n");
 208                        goto put_device;
 209                }
 210        }
 211
 212        if (irq) {
 213                struct resource r = {
 214                        .start = irq,
 215                        .flags = IORESOURCE_IRQ,
 216                };
 217
 218                status = platform_device_add_resources(pdev, &r, 1);
 219                if (status < 0) {
 220                        dev_dbg(&pdev->dev, "can't add irq\n");
 221                        goto put_device;
 222                }
 223        }
 224
 225        status = platform_device_add(pdev);
 226        if (status)
 227                goto put_device;
 228
 229        return &pdev->dev;
 230
 231put_device:
 232        platform_device_put(pdev);
 233        dev_err(&client->dev, "failed to add device %s\n", name);
 234        return ERR_PTR(status);
 235}
 236
 237static int add_children(struct i2c_client *client)
 238{
 239        static const struct {
 240                int offset;
 241                char *label;
 242        } config_inputs[] = {
 243                /* 8 == right after the LEDs */
 244                { 8 + 0, "sw6_1", },
 245                { 8 + 1, "sw6_2", },
 246                { 8 + 2, "sw6_3", },
 247                { 8 + 3, "sw6_4", },
 248                { 8 + 4, "NTSC/nPAL", },
 249        };
 250
 251        struct device   *child;
 252        int             status;
 253        int             i;
 254
 255        /* GPIO-ish stuff */
 256        dm355evm_msp_gpio.parent = &client->dev;
 257        status = gpiochip_add_data(&dm355evm_msp_gpio, NULL);
 258        if (status < 0)
 259                return status;
 260
 261        /* LED output */
 262        if (msp_has_leds()) {
 263#define GPIO_LED(l)     .name = l, .active_low = true
 264                static struct gpio_led evm_leds[] = {
 265                        { GPIO_LED("dm355evm::ds14"),
 266                                .default_trigger = "heartbeat", },
 267                        { GPIO_LED("dm355evm::ds15"),
 268                                .default_trigger = "mmc0", },
 269                        { GPIO_LED("dm355evm::ds16"),
 270                                /* could also be a CE-ATA drive */
 271                                .default_trigger = "mmc1", },
 272                        { GPIO_LED("dm355evm::ds17"),
 273                                .default_trigger = "nand-disk", },
 274                        { GPIO_LED("dm355evm::ds18"), },
 275                        { GPIO_LED("dm355evm::ds19"), },
 276                        { GPIO_LED("dm355evm::ds20"), },
 277                        { GPIO_LED("dm355evm::ds21"), },
 278                };
 279#undef GPIO_LED
 280
 281                struct gpio_led_platform_data evm_led_data = {
 282                        .num_leds       = ARRAY_SIZE(evm_leds),
 283                        .leds           = evm_leds,
 284                };
 285
 286                for (i = 0; i < ARRAY_SIZE(evm_leds); i++)
 287                        evm_leds[i].gpio = i + dm355evm_msp_gpio.base;
 288
 289                /* NOTE:  these are the only fully programmable LEDs
 290                 * on the board, since GPIO-61/ds22 (and many signals
 291                 * going to DC7) must be used for AEMIF address lines
 292                 * unless the top 1 GB of NAND is unused...
 293                 */
 294                child = add_child(client, "leds-gpio",
 295                                &evm_led_data, sizeof(evm_led_data),
 296                                false, 0);
 297                if (IS_ERR(child))
 298                        return PTR_ERR(child);
 299        }
 300
 301        /* configuration inputs */
 302        for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
 303                int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
 304
 305                gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label);
 306
 307                /* make it easy for userspace to see these */
 308                gpio_export(gpio, false);
 309        }
 310
 311        /* MMC/SD inputs -- right after the last config input */
 312        if (dev_get_platdata(&client->dev)) {
 313                void (*mmcsd_setup)(unsigned) = dev_get_platdata(&client->dev);
 314
 315                mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5);
 316        }
 317
 318        /* RTC is a 32 bit counter, no alarm */
 319        if (msp_has_rtc()) {
 320                child = add_child(client, "rtc-dm355evm",
 321                                NULL, 0, false, 0);
 322                if (IS_ERR(child))
 323                        return PTR_ERR(child);
 324        }
 325
 326        /* input from buttons and IR remote (uses the IRQ) */
 327        if (msp_has_keyboard()) {
 328                child = add_child(client, "dm355evm_keys",
 329                                NULL, 0, true, client->irq);
 330                if (IS_ERR(child))
 331                        return PTR_ERR(child);
 332        }
 333
 334        return 0;
 335}
 336
 337/*----------------------------------------------------------------------*/
 338
 339static void dm355evm_command(unsigned command)
 340{
 341        int status;
 342
 343        status = dm355evm_msp_write(command, DM355EVM_MSP_COMMAND);
 344        if (status < 0)
 345                dev_err(&msp430->dev, "command %d failure %d\n",
 346                                command, status);
 347}
 348
 349static void dm355evm_power_off(void)
 350{
 351        dm355evm_command(MSP_COMMAND_POWEROFF);
 352}
 353
 354static int dm355evm_msp_remove(struct i2c_client *client)
 355{
 356        pm_power_off = NULL;
 357        msp430 = NULL;
 358        return 0;
 359}
 360
 361static int
 362dm355evm_msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 363{
 364        int             status;
 365        const char      *video = msp_has_tvp() ? "TVP5146" : "imager";
 366
 367        if (msp430)
 368                return -EBUSY;
 369        msp430 = client;
 370
 371        /* display revision status; doubles as sanity check */
 372        status = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
 373        if (status < 0)
 374                goto fail;
 375        dev_info(&client->dev, "firmware v.%02X, %s as video-in\n",
 376                        status, video);
 377
 378        /* mux video input:  either tvp5146 or some external imager */
 379        status = dm355evm_msp_write(msp_has_tvp() ? 0 : MSP_VIDEO_IMAGER,
 380                        DM355EVM_MSP_VIDEO_IN);
 381        if (status < 0)
 382                dev_warn(&client->dev, "error %d muxing %s as video-in\n",
 383                        status, video);
 384
 385        /* init LED cache, and turn off the LEDs */
 386        msp_led_cache = 0xff;
 387        dm355evm_msp_write(msp_led_cache, DM355EVM_MSP_LED);
 388
 389        /* export capabilities we support */
 390        status = add_children(client);
 391        if (status < 0)
 392                goto fail;
 393
 394        /* PM hookup */
 395        pm_power_off = dm355evm_power_off;
 396
 397        return 0;
 398
 399fail:
 400        /* FIXME remove children ... */
 401        dm355evm_msp_remove(client);
 402        return status;
 403}
 404
 405static const struct i2c_device_id dm355evm_msp_ids[] = {
 406        { "dm355evm_msp", 0 },
 407        { /* end of list */ },
 408};
 409MODULE_DEVICE_TABLE(i2c, dm355evm_msp_ids);
 410
 411static struct i2c_driver dm355evm_msp_driver = {
 412        .driver.name    = "dm355evm_msp",
 413        .id_table       = dm355evm_msp_ids,
 414        .probe          = dm355evm_msp_probe,
 415        .remove         = dm355evm_msp_remove,
 416};
 417
 418static int __init dm355evm_msp_init(void)
 419{
 420        return i2c_add_driver(&dm355evm_msp_driver);
 421}
 422subsys_initcall(dm355evm_msp_init);
 423
 424static void __exit dm355evm_msp_exit(void)
 425{
 426        i2c_del_driver(&dm355evm_msp_driver);
 427}
 428module_exit(dm355evm_msp_exit);
 429
 430MODULE_DESCRIPTION("Interface to MSP430 firmware on DM355EVM");
 431MODULE_LICENSE("GPL");
 432