0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/adb.h>
0013 #include <linux/pmu.h>
0014
0015 #include "ams.h"
0016
0017
0018 #define AMS_X 0x00
0019 #define AMS_Y 0x01
0020 #define AMS_Z 0x02
0021
0022
0023 #define AMS_VENDOR 0x03
0024
0025
0026 #define AMS_FF_CLEAR 0x04
0027 #define AMS_FF_ENABLE 0x05
0028 #define AMS_FF_LOW_LIMIT 0x06
0029 #define AMS_FF_DEBOUNCE 0x07
0030
0031
0032 #define AMS_SHOCK_CLEAR 0x08
0033 #define AMS_SHOCK_ENABLE 0x09
0034 #define AMS_SHOCK_HIGH_LIMIT 0x0a
0035 #define AMS_SHOCK_DEBOUNCE 0x0b
0036
0037
0038 #define AMS_CONTROL 0x0c
0039
0040 static u8 ams_pmu_cmd;
0041
0042 static void ams_pmu_req_complete(struct adb_request *req)
0043 {
0044 complete((struct completion *)req->arg);
0045 }
0046
0047
0048 static void ams_pmu_set_register(u8 reg, u8 value)
0049 {
0050 static struct adb_request req;
0051 DECLARE_COMPLETION(req_complete);
0052
0053 req.arg = &req_complete;
0054 if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
0055 return;
0056
0057 wait_for_completion(&req_complete);
0058 }
0059
0060
0061 static u8 ams_pmu_get_register(u8 reg)
0062 {
0063 static struct adb_request req;
0064 DECLARE_COMPLETION(req_complete);
0065
0066 req.arg = &req_complete;
0067 if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
0068 return 0;
0069
0070 wait_for_completion(&req_complete);
0071
0072 if (req.reply_len > 0)
0073 return req.reply[0];
0074 else
0075 return 0;
0076 }
0077
0078
0079 static void ams_pmu_set_irq(enum ams_irq reg, char enable)
0080 {
0081 if (reg & AMS_IRQ_FREEFALL) {
0082 u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
0083 if (enable)
0084 val |= 0x80;
0085 else
0086 val &= ~0x80;
0087 ams_pmu_set_register(AMS_FF_ENABLE, val);
0088 }
0089
0090 if (reg & AMS_IRQ_SHOCK) {
0091 u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
0092 if (enable)
0093 val |= 0x80;
0094 else
0095 val &= ~0x80;
0096 ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
0097 }
0098
0099 if (reg & AMS_IRQ_GLOBAL) {
0100 u8 val = ams_pmu_get_register(AMS_CONTROL);
0101 if (enable)
0102 val |= 0x80;
0103 else
0104 val &= ~0x80;
0105 ams_pmu_set_register(AMS_CONTROL, val);
0106 }
0107 }
0108
0109 static void ams_pmu_clear_irq(enum ams_irq reg)
0110 {
0111 if (reg & AMS_IRQ_FREEFALL)
0112 ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
0113
0114 if (reg & AMS_IRQ_SHOCK)
0115 ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
0116 }
0117
0118 static u8 ams_pmu_get_vendor(void)
0119 {
0120 return ams_pmu_get_register(AMS_VENDOR);
0121 }
0122
0123 static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
0124 {
0125 *x = ams_pmu_get_register(AMS_X);
0126 *y = ams_pmu_get_register(AMS_Y);
0127 *z = ams_pmu_get_register(AMS_Z);
0128 }
0129
0130 static void ams_pmu_exit(void)
0131 {
0132 ams_sensor_detach();
0133
0134
0135 ams_pmu_set_irq(AMS_IRQ_ALL, 0);
0136
0137
0138 ams_pmu_clear_irq(AMS_IRQ_ALL);
0139
0140 ams_info.has_device = 0;
0141
0142 printk(KERN_INFO "ams: Unloading\n");
0143 }
0144
0145 int __init ams_pmu_init(struct device_node *np)
0146 {
0147 const u32 *prop;
0148 int result;
0149
0150
0151 ams_info.of_node = np;
0152 ams_info.exit = ams_pmu_exit;
0153 ams_info.get_vendor = ams_pmu_get_vendor;
0154 ams_info.get_xyz = ams_pmu_get_xyz;
0155 ams_info.clear_irq = ams_pmu_clear_irq;
0156 ams_info.bustype = BUS_HOST;
0157
0158
0159 prop = of_get_property(ams_info.of_node, "reg", NULL);
0160 if (!prop)
0161 return -ENODEV;
0162
0163 ams_pmu_cmd = ((*prop) >> 8) & 0xff;
0164
0165
0166 ams_pmu_set_irq(AMS_IRQ_ALL, 0);
0167
0168
0169 ams_pmu_clear_irq(AMS_IRQ_ALL);
0170
0171 result = ams_sensor_attach();
0172 if (result < 0)
0173 return result;
0174
0175
0176 ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
0177 ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
0178 ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
0179
0180 ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
0181 ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
0182 ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
0183
0184 ams_pmu_set_register(AMS_CONTROL, 0x4f);
0185
0186
0187 ams_pmu_clear_irq(AMS_IRQ_ALL);
0188
0189 ams_info.has_device = 1;
0190
0191
0192 ams_pmu_set_irq(AMS_IRQ_ALL, 1);
0193
0194 printk(KERN_INFO "ams: Found PMU based motion sensor\n");
0195
0196 return 0;
0197 }