^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Apple Motion Sensor driver (PMU variant)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/adb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/pmu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "ams.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /* Attitude */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define AMS_X 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define AMS_Y 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define AMS_Z 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Not exactly known, maybe chip vendor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define AMS_VENDOR 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Freefall registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define AMS_FF_CLEAR 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define AMS_FF_ENABLE 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define AMS_FF_LOW_LIMIT 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define AMS_FF_DEBOUNCE 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Shock registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define AMS_SHOCK_CLEAR 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define AMS_SHOCK_ENABLE 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define AMS_SHOCK_HIGH_LIMIT 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define AMS_SHOCK_DEBOUNCE 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Global interrupt and power control register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define AMS_CONTROL 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static u8 ams_pmu_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static void ams_pmu_req_complete(struct adb_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) complete((struct completion *)req->arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* Only call this function from task context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static void ams_pmu_set_register(u8 reg, u8 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static struct adb_request req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) DECLARE_COMPLETION(req_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) req.arg = &req_complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) wait_for_completion(&req_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* Only call this function from task context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static u8 ams_pmu_get_register(u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static struct adb_request req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) DECLARE_COMPLETION(req_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) req.arg = &req_complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) wait_for_completion(&req_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (req.reply_len > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return req.reply[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Enables or disables the specified interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void ams_pmu_set_irq(enum ams_irq reg, char enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (reg & AMS_IRQ_FREEFALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) val |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) val &= ~0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ams_pmu_set_register(AMS_FF_ENABLE, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (reg & AMS_IRQ_SHOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) val |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) val &= ~0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (reg & AMS_IRQ_GLOBAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u8 val = ams_pmu_get_register(AMS_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) val |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) val &= ~0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ams_pmu_set_register(AMS_CONTROL, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static void ams_pmu_clear_irq(enum ams_irq reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (reg & AMS_IRQ_FREEFALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (reg & AMS_IRQ_SHOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static u8 ams_pmu_get_vendor(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return ams_pmu_get_register(AMS_VENDOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *x = ams_pmu_get_register(AMS_X);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) *y = ams_pmu_get_register(AMS_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) *z = ams_pmu_get_register(AMS_Z);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static void ams_pmu_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ams_sensor_detach();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Disable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ams_pmu_set_irq(AMS_IRQ_ALL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Clear interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ams_pmu_clear_irq(AMS_IRQ_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ams_info.has_device = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) printk(KERN_INFO "ams: Unloading\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int __init ams_pmu_init(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const u32 *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Set implementation stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ams_info.of_node = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ams_info.exit = ams_pmu_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ams_info.get_vendor = ams_pmu_get_vendor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ams_info.get_xyz = ams_pmu_get_xyz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ams_info.clear_irq = ams_pmu_clear_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ams_info.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* Get PMU command, should be 0x4e, but we can never know */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) prop = of_get_property(ams_info.of_node, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ams_pmu_cmd = ((*prop) >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Disable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) ams_pmu_set_irq(AMS_IRQ_ALL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Clear interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ams_pmu_clear_irq(AMS_IRQ_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) result = ams_sensor_attach();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Set default values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ams_pmu_set_register(AMS_CONTROL, 0x4f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* Clear interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ams_pmu_clear_irq(AMS_IRQ_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ams_info.has_device = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /* Enable interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ams_pmu_set_irq(AMS_IRQ_ALL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) printk(KERN_INFO "ams: Found PMU based motion sensor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }