summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/digiPiper/adc121c027.c
blob: 17564bcd7a66076fa0d8a307ac3225c9183aacb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
    adc121C027.c - Analog to Digital converter integrated into Piper.

    Copyright (C) 2009 Digi International <sales2@digi.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>

#include "airohaCalibration.h"
#include "pipermain.h"

/* Addresses to scan: none, device is not autodetected */
/* static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; */

#define ADC_I2C_ADDR		(0x51)
#define ADC_CYCLE_TIME		(0x20)

static const unsigned short normal_i2c[] = { ADC_I2C_ADDR, I2C_CLIENT_END };
static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };

static struct i2c_client_address_data addr = {
	.normal_i2c = normal_i2c,
	.probe = dummy_i2c_addrlist,
	.ignore = dummy_i2c_addrlist,
};

enum adc121C027_cmd {
        ADC_RESULT              = 0,
        ADC_ALERT_STATUS        = 1,
        ADC_CONFIGURATION       = 2,
        ADC_LOW_LIMIT           = 3,
        ADC_HIGH_LIMIT          = 4,
        ADC_HYSTERESIS          = 5,
        ADC_LOWEST_VALUE        = 6,
        ADC_HIGHEST_VALUE       = 7,
};

static u16 adc121C027_read_peak(struct airohaCalibrationData *cal)
{
	struct i2c_client *i2cclient = (struct i2c_client *)cal->priv;

	return be16_to_cpu(i2c_smbus_read_word_data(i2cclient, ADC_HIGHEST_VALUE));
}

static void adc121C027_clear_peak(struct airohaCalibrationData *cal)
{
	struct i2c_client *i2cclient = (struct i2c_client *)cal->priv;

	i2c_smbus_write_word_data(i2cclient, ADC_HIGHEST_VALUE, 0);
}

static u16 adc121C027_read_last_sample(struct airohaCalibrationData *cal)
{
	struct i2c_client *i2cclient = (struct i2c_client *)cal->priv;

	return be16_to_cpu(i2c_smbus_read_word_data(i2cclient, ADC_RESULT));
}

static int adc121C027_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	return (client->addr != ADC_I2C_ADDR) ? -EINVAL : 0;
}

static int adc121C027_remove(struct i2c_client *client)
{
	/* Real shut down will be done by adc121C027_shutdown() */
	return 0;
}

static const struct i2c_device_id adc121C027_id[] = {
	{ "adc121C027", 0 },
	{}
};

static struct i2c_driver adc121C027_driver = {
	.driver = {
		.name   = "adc121C027",
	},
	.probe          = adc121C027_probe,
	.remove         =  __devexit_p(adc121C027_remove),
	.id_table       = adc121C027_id,
	.address_data   = &addr,
};

/* Turn on automatic A/D process by setting a non zero cycle time */
static void adc121C027_hw_init(struct airohaCalibrationData *cal)
{
	struct i2c_client *i2cclient = (struct i2c_client *)cal->priv;

	i2c_smbus_write_word_data(i2cclient, ADC_CONFIGURATION, ADC_CYCLE_TIME);
}

void adc121C027_shutdown(struct airohaCalibrationData *cal)
{
	struct i2c_client *i2cclient = (struct i2c_client *)cal->priv;

	if (i2cclient) {
		i2c_unregister_device(i2cclient);
		cal->priv = NULL;
	}
	i2c_del_driver(&adc121C027_driver);
}

int adc121C027_init(struct airohaCalibrationData *cal, int i2cadapter)
{
	struct i2c_board_info board_info = {
		.type = "adc121C027",
		.addr = ADC_I2C_ADDR,
	};
	struct i2c_adapter *adapter;
	struct i2c_client *adc_i2c_client;
	int ret;

	ret = i2c_add_driver(&adc121C027_driver);
	if (ret) {
		printk(KERN_WARNING PIPER_DRIVER_NAME
			": error adding driver adc121C027_driver (%d)\n", ret);
		return ret;
	}

	adapter = i2c_get_adapter(i2cadapter);
	if (!adapter) {
		printk(KERN_WARNING PIPER_DRIVER_NAME
			": error getting i2c adapter\n");
		return -EINVAL;
	}
    
	adc_i2c_client = i2c_new_device(adapter, &board_info);
	if (!adc_i2c_client) {
		printk(KERN_WARNING PIPER_DRIVER_NAME
			": error creating new i2c client\n");
		return -EINVAL;
	}

	cal->priv = (void *)adc_i2c_client;
	adc121C027_hw_init(cal);

	cal->cops = kmalloc(sizeof(struct calibration_ops), GFP_KERNEL);
	if (!cal->cops) {
		printk(KERN_WARNING PIPER_DRIVER_NAME
			": unable to allocate memory for cal->cops\n");
		return -ENOMEM;
	}
	cal->cops->adc_read_peak = adc121C027_read_peak;
	cal->cops->adc_clear_peak = adc121C027_clear_peak;
	cal->cops->adc_read_last_val = adc121C027_read_last_sample;
	cal->cops->adc_shutdown = adc121C027_shutdown;
    
	return 0;
}    
EXPORT_SYMBOL_GPL(adc121C027_init);