1d50f8f33SHaojian Zhuang /* 2d50f8f33SHaojian Zhuang * I2C driver for Maxim MAX8925 3d50f8f33SHaojian Zhuang * 4d50f8f33SHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5d50f8f33SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6d50f8f33SHaojian Zhuang * 7d50f8f33SHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8d50f8f33SHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9d50f8f33SHaojian Zhuang * published by the Free Software Foundation. 10d50f8f33SHaojian Zhuang */ 11d50f8f33SHaojian Zhuang #include <linux/kernel.h> 12d50f8f33SHaojian Zhuang #include <linux/module.h> 13d50f8f33SHaojian Zhuang #include <linux/platform_device.h> 14d50f8f33SHaojian Zhuang #include <linux/i2c.h> 15d50f8f33SHaojian Zhuang #include <linux/mfd/max8925.h> 16d50f8f33SHaojian Zhuang 17*b13c0df5SHaojian Zhuang #define RTC_I2C_ADDR 0x68 18*b13c0df5SHaojian Zhuang #define ADC_I2C_ADDR 0x47 19*b13c0df5SHaojian Zhuang 20d50f8f33SHaojian Zhuang static inline int max8925_read_device(struct i2c_client *i2c, 21d50f8f33SHaojian Zhuang int reg, int bytes, void *dest) 22d50f8f33SHaojian Zhuang { 23d50f8f33SHaojian Zhuang int ret; 24d50f8f33SHaojian Zhuang 25*b13c0df5SHaojian Zhuang if (bytes > 1) 26*b13c0df5SHaojian Zhuang ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest); 27*b13c0df5SHaojian Zhuang else { 28*b13c0df5SHaojian Zhuang ret = i2c_smbus_read_byte_data(i2c, reg); 29d50f8f33SHaojian Zhuang if (ret < 0) 30d50f8f33SHaojian Zhuang return ret; 31*b13c0df5SHaojian Zhuang *(unsigned char *)dest = (unsigned char)ret; 32*b13c0df5SHaojian Zhuang } 33d50f8f33SHaojian Zhuang return ret; 34d50f8f33SHaojian Zhuang } 35d50f8f33SHaojian Zhuang 36d50f8f33SHaojian Zhuang static inline int max8925_write_device(struct i2c_client *i2c, 37d50f8f33SHaojian Zhuang int reg, int bytes, void *src) 38d50f8f33SHaojian Zhuang { 39d50f8f33SHaojian Zhuang unsigned char buf[bytes + 1]; 40d50f8f33SHaojian Zhuang int ret; 41d50f8f33SHaojian Zhuang 42d50f8f33SHaojian Zhuang buf[0] = (unsigned char)reg; 43d50f8f33SHaojian Zhuang memcpy(&buf[1], src, bytes); 44d50f8f33SHaojian Zhuang 45d50f8f33SHaojian Zhuang ret = i2c_master_send(i2c, buf, bytes + 1); 46d50f8f33SHaojian Zhuang if (ret < 0) 47d50f8f33SHaojian Zhuang return ret; 48d50f8f33SHaojian Zhuang return 0; 49d50f8f33SHaojian Zhuang } 50d50f8f33SHaojian Zhuang 51d50f8f33SHaojian Zhuang int max8925_reg_read(struct i2c_client *i2c, int reg) 52d50f8f33SHaojian Zhuang { 53d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 54*b13c0df5SHaojian Zhuang unsigned char data = 0; 55d50f8f33SHaojian Zhuang int ret; 56d50f8f33SHaojian Zhuang 57d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 58d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, 1, &data); 59d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 60d50f8f33SHaojian Zhuang 61d50f8f33SHaojian Zhuang if (ret < 0) 62d50f8f33SHaojian Zhuang return ret; 63d50f8f33SHaojian Zhuang else 64d50f8f33SHaojian Zhuang return (int)data; 65d50f8f33SHaojian Zhuang } 66d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_reg_read); 67d50f8f33SHaojian Zhuang 68d50f8f33SHaojian Zhuang int max8925_reg_write(struct i2c_client *i2c, int reg, 69d50f8f33SHaojian Zhuang unsigned char data) 70d50f8f33SHaojian Zhuang { 71d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 72d50f8f33SHaojian Zhuang int ret; 73d50f8f33SHaojian Zhuang 74d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 75d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, 1, &data); 76d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 77d50f8f33SHaojian Zhuang 78d50f8f33SHaojian Zhuang return ret; 79d50f8f33SHaojian Zhuang } 80d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_reg_write); 81d50f8f33SHaojian Zhuang 82d50f8f33SHaojian Zhuang int max8925_bulk_read(struct i2c_client *i2c, int reg, 83d50f8f33SHaojian Zhuang int count, unsigned char *buf) 84d50f8f33SHaojian Zhuang { 85d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 86d50f8f33SHaojian Zhuang int ret; 87d50f8f33SHaojian Zhuang 88d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 89d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, count, buf); 90d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 91d50f8f33SHaojian Zhuang 92d50f8f33SHaojian Zhuang return ret; 93d50f8f33SHaojian Zhuang } 94d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_bulk_read); 95d50f8f33SHaojian Zhuang 96d50f8f33SHaojian Zhuang int max8925_bulk_write(struct i2c_client *i2c, int reg, 97d50f8f33SHaojian Zhuang int count, unsigned char *buf) 98d50f8f33SHaojian Zhuang { 99d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 100d50f8f33SHaojian Zhuang int ret; 101d50f8f33SHaojian Zhuang 102d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 103d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, count, buf); 104d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 105d50f8f33SHaojian Zhuang 106d50f8f33SHaojian Zhuang return ret; 107d50f8f33SHaojian Zhuang } 108d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_bulk_write); 109d50f8f33SHaojian Zhuang 110d50f8f33SHaojian Zhuang int max8925_set_bits(struct i2c_client *i2c, int reg, 111d50f8f33SHaojian Zhuang unsigned char mask, unsigned char data) 112d50f8f33SHaojian Zhuang { 113d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 114d50f8f33SHaojian Zhuang unsigned char value; 115d50f8f33SHaojian Zhuang int ret; 116d50f8f33SHaojian Zhuang 117d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 118d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, 1, &value); 119d50f8f33SHaojian Zhuang if (ret < 0) 120d50f8f33SHaojian Zhuang goto out; 121d50f8f33SHaojian Zhuang value &= ~mask; 122d50f8f33SHaojian Zhuang value |= data; 123d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, 1, &value); 124d50f8f33SHaojian Zhuang out: 125d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 126d50f8f33SHaojian Zhuang return ret; 127d50f8f33SHaojian Zhuang } 128d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_set_bits); 129d50f8f33SHaojian Zhuang 130d50f8f33SHaojian Zhuang 131d50f8f33SHaojian Zhuang static const struct i2c_device_id max8925_id_table[] = { 132d50f8f33SHaojian Zhuang { "max8925", 0 }, 133*b13c0df5SHaojian Zhuang { }, 134d50f8f33SHaojian Zhuang }; 135d50f8f33SHaojian Zhuang MODULE_DEVICE_TABLE(i2c, max8925_id_table); 136d50f8f33SHaojian Zhuang 137d50f8f33SHaojian Zhuang static int __devinit max8925_probe(struct i2c_client *client, 138d50f8f33SHaojian Zhuang const struct i2c_device_id *id) 139d50f8f33SHaojian Zhuang { 140d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata = client->dev.platform_data; 141*b13c0df5SHaojian Zhuang static struct max8925_chip *chip; 142d50f8f33SHaojian Zhuang 143d50f8f33SHaojian Zhuang if (!pdata) { 144d50f8f33SHaojian Zhuang pr_info("%s: platform data is missing\n", __func__); 145d50f8f33SHaojian Zhuang return -EINVAL; 146d50f8f33SHaojian Zhuang } 147d50f8f33SHaojian Zhuang 148d50f8f33SHaojian Zhuang chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL); 149d50f8f33SHaojian Zhuang if (chip == NULL) 150d50f8f33SHaojian Zhuang return -ENOMEM; 151d50f8f33SHaojian Zhuang chip->i2c = client; 152d50f8f33SHaojian Zhuang chip->dev = &client->dev; 153*b13c0df5SHaojian Zhuang i2c_set_clientdata(client, chip); 154d50f8f33SHaojian Zhuang dev_set_drvdata(chip->dev, chip); 155*b13c0df5SHaojian Zhuang mutex_init(&chip->io_lock); 156*b13c0df5SHaojian Zhuang 157*b13c0df5SHaojian Zhuang chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR); 158*b13c0df5SHaojian Zhuang i2c_set_clientdata(chip->rtc, chip); 159*b13c0df5SHaojian Zhuang 160*b13c0df5SHaojian Zhuang chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR); 161*b13c0df5SHaojian Zhuang i2c_set_clientdata(chip->adc, chip); 162*b13c0df5SHaojian Zhuang 163d50f8f33SHaojian Zhuang max8925_device_init(chip, pdata); 164d50f8f33SHaojian Zhuang 165d50f8f33SHaojian Zhuang return 0; 166d50f8f33SHaojian Zhuang } 167d50f8f33SHaojian Zhuang 168d50f8f33SHaojian Zhuang static int __devexit max8925_remove(struct i2c_client *client) 169d50f8f33SHaojian Zhuang { 170d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(client); 171d50f8f33SHaojian Zhuang 172d50f8f33SHaojian Zhuang max8925_device_exit(chip); 173*b13c0df5SHaojian Zhuang i2c_unregister_device(chip->adc); 174*b13c0df5SHaojian Zhuang i2c_unregister_device(chip->rtc); 175*b13c0df5SHaojian Zhuang i2c_set_clientdata(chip->adc, NULL); 176*b13c0df5SHaojian Zhuang i2c_set_clientdata(chip->rtc, NULL); 177*b13c0df5SHaojian Zhuang i2c_set_clientdata(chip->i2c, NULL); 178d50f8f33SHaojian Zhuang kfree(chip); 179d50f8f33SHaojian Zhuang return 0; 180d50f8f33SHaojian Zhuang } 181d50f8f33SHaojian Zhuang 182d50f8f33SHaojian Zhuang static struct i2c_driver max8925_driver = { 183d50f8f33SHaojian Zhuang .driver = { 184d50f8f33SHaojian Zhuang .name = "max8925", 185d50f8f33SHaojian Zhuang .owner = THIS_MODULE, 186d50f8f33SHaojian Zhuang }, 187d50f8f33SHaojian Zhuang .probe = max8925_probe, 188d50f8f33SHaojian Zhuang .remove = __devexit_p(max8925_remove), 189d50f8f33SHaojian Zhuang .id_table = max8925_id_table, 190d50f8f33SHaojian Zhuang }; 191d50f8f33SHaojian Zhuang 192d50f8f33SHaojian Zhuang static int __init max8925_i2c_init(void) 193d50f8f33SHaojian Zhuang { 194d50f8f33SHaojian Zhuang int ret; 195d50f8f33SHaojian Zhuang 196d50f8f33SHaojian Zhuang ret = i2c_add_driver(&max8925_driver); 197d50f8f33SHaojian Zhuang if (ret != 0) 198d50f8f33SHaojian Zhuang pr_err("Failed to register MAX8925 I2C driver: %d\n", ret); 199d50f8f33SHaojian Zhuang return ret; 200d50f8f33SHaojian Zhuang } 201d50f8f33SHaojian Zhuang subsys_initcall(max8925_i2c_init); 202d50f8f33SHaojian Zhuang 203d50f8f33SHaojian Zhuang static void __exit max8925_i2c_exit(void) 204d50f8f33SHaojian Zhuang { 205d50f8f33SHaojian Zhuang i2c_del_driver(&max8925_driver); 206d50f8f33SHaojian Zhuang } 207d50f8f33SHaojian Zhuang module_exit(max8925_i2c_exit); 208d50f8f33SHaojian Zhuang 209d50f8f33SHaojian Zhuang MODULE_DESCRIPTION("I2C Driver for Maxim 8925"); 210d50f8f33SHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 211d50f8f33SHaojian Zhuang MODULE_LICENSE("GPL"); 212