root/drivers/macintosh/ams/ams-pmu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ams_pmu_req_complete
  2. ams_pmu_set_register
  3. ams_pmu_get_register
  4. ams_pmu_set_irq
  5. ams_pmu_clear_irq
  6. ams_pmu_get_vendor
  7. ams_pmu_get_xyz
  8. ams_pmu_exit
  9. ams_pmu_init

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

/* [<][>][^][v][top][bottom][index][help] */