linux/arch/arm/mach-pxa/akita-ioexp.c
<<
>>
Prefs
   1/*
   2 * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
   3 * (uses a Maxim MAX7310 8 Port IO Expander)
   4 *
   5 * Copyright 2005 Openedhand Ltd.
   6 *
   7 * Author: Richard Purdie <richard@openedhand.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/init.h>
  17#include <linux/platform_device.h>
  18#include <linux/module.h>
  19#include <linux/i2c.h>
  20#include <linux/slab.h>
  21#include <linux/workqueue.h>
  22#include <asm/arch/akita.h>
  23
  24/* MAX7310 Regiser Map */
  25#define MAX7310_INPUT    0x00
  26#define MAX7310_OUTPUT   0x01
  27#define MAX7310_POLINV   0x02
  28#define MAX7310_IODIR    0x03 /* 1 = Input, 0 = Output */
  29#define MAX7310_TIMEOUT  0x04
  30
  31/* Addresses to scan */
  32static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
  33
  34/* I2C Magic */
  35I2C_CLIENT_INSMOD;
  36
  37static int max7310_write(struct i2c_client *client, int address, int data);
  38static struct i2c_client max7310_template;
  39static void akita_ioexp_work(struct work_struct *private_);
  40
  41static struct device *akita_ioexp_device;
  42static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
  43DECLARE_WORK(akita_ioexp, akita_ioexp_work);
  44
  45
  46/*
  47 * MAX7310 Access
  48 */
  49static int max7310_config(struct device *dev, int iomode, int polarity)
  50{
  51        int ret;
  52        struct i2c_client *client = to_i2c_client(dev);
  53
  54        ret = max7310_write(client, MAX7310_POLINV, polarity);
  55        if (ret < 0)
  56                return ret;
  57        ret = max7310_write(client, MAX7310_IODIR, iomode);
  58        return ret;
  59}
  60
  61static int max7310_set_ouputs(struct device *dev, int outputs)
  62{
  63        struct i2c_client *client = to_i2c_client(dev);
  64
  65        return max7310_write(client, MAX7310_OUTPUT, outputs);
  66}
  67
  68/*
  69 * I2C Functions
  70 */
  71static int max7310_write(struct i2c_client *client, int address, int value)
  72{
  73        u8 data[2];
  74
  75        data[0] = address & 0xff;
  76        data[1] = value & 0xff;
  77
  78        if (i2c_master_send(client, data, 2) == 2)
  79                return 0;
  80        return -1;
  81}
  82
  83static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
  84{
  85        struct i2c_client *new_client;
  86        int err;
  87
  88        if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
  89                return -ENOMEM;
  90
  91        max7310_template.adapter = adapter;
  92        max7310_template.addr = address;
  93
  94        memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
  95
  96        if ((err = i2c_attach_client(new_client))) {
  97                kfree(new_client);
  98                return err;
  99        }
 100
 101        max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
 102        akita_ioexp_device = &new_client->dev;
 103        schedule_work(&akita_ioexp);
 104
 105        return 0;
 106}
 107
 108static int max7310_attach_adapter(struct i2c_adapter *adapter)
 109{
 110        return i2c_probe(adapter, &addr_data, max7310_detect);
 111}
 112
 113static int max7310_detach_client(struct i2c_client *client)
 114{
 115        int err;
 116
 117        akita_ioexp_device = NULL;
 118
 119        if ((err = i2c_detach_client(client)))
 120                return err;
 121
 122        kfree(client);
 123        return 0;
 124}
 125
 126static struct i2c_driver max7310_i2c_driver = {
 127        .driver = {
 128                .name   = "akita-max7310",
 129        },
 130        .id             = I2C_DRIVERID_AKITAIOEXP,
 131        .attach_adapter = max7310_attach_adapter,
 132        .detach_client  = max7310_detach_client,
 133};
 134
 135static struct i2c_client max7310_template = {
 136        name:   "akita-max7310",
 137        driver: &max7310_i2c_driver,
 138};
 139
 140void akita_set_ioexp(struct device *dev, unsigned char bit)
 141{
 142        ioexp_output_value |= bit;
 143
 144        if (akita_ioexp_device)
 145                schedule_work(&akita_ioexp);
 146        return;
 147}
 148
 149void akita_reset_ioexp(struct device *dev, unsigned char bit)
 150{
 151        ioexp_output_value &= ~bit;
 152
 153        if (akita_ioexp_device)
 154                schedule_work(&akita_ioexp);
 155        return;
 156}
 157
 158EXPORT_SYMBOL(akita_set_ioexp);
 159EXPORT_SYMBOL(akita_reset_ioexp);
 160
 161static void akita_ioexp_work(struct work_struct *private_)
 162{
 163        if (akita_ioexp_device)
 164                max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
 165}
 166
 167
 168#ifdef CONFIG_PM
 169static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
 170{
 171        flush_scheduled_work();
 172        return 0;
 173}
 174
 175static int akita_ioexp_resume(struct platform_device *pdev)
 176{
 177        schedule_work(&akita_ioexp);
 178        return 0;
 179}
 180#else
 181#define akita_ioexp_suspend NULL
 182#define akita_ioexp_resume NULL
 183#endif
 184
 185static int __init akita_ioexp_probe(struct platform_device *pdev)
 186{
 187        return i2c_add_driver(&max7310_i2c_driver);
 188}
 189
 190static int akita_ioexp_remove(struct platform_device *pdev)
 191{
 192        i2c_del_driver(&max7310_i2c_driver);
 193        return 0;
 194}
 195
 196static struct platform_driver akita_ioexp_driver = {
 197        .probe          = akita_ioexp_probe,
 198        .remove         = akita_ioexp_remove,
 199        .suspend        = akita_ioexp_suspend,
 200        .resume         = akita_ioexp_resume,
 201        .driver         = {
 202                .name   = "akita-ioexp",
 203        },
 204};
 205
 206static int __init akita_ioexp_init(void)
 207{
 208        return platform_driver_register(&akita_ioexp_driver);
 209}
 210
 211static void __exit akita_ioexp_exit(void)
 212{
 213        platform_driver_unregister(&akita_ioexp_driver);
 214}
 215
 216MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
 217MODULE_DESCRIPTION("Akita IO-Expander driver");
 218MODULE_LICENSE("GPL");
 219
 220fs_initcall(akita_ioexp_init);
 221module_exit(akita_ioexp_exit);
 222
 223