2 #include <minix/drivers.h>
4 #include <minix/i2cdriver.h>
7 #include <sys/signal.h>
9 /* Register Addresses */
10 #define CHIPID_REG 0x00
11 #define PPATH_REG 0x01
13 #define CHGCONFIG0_REG 0x03
14 #define CHGCONFIG1_REG 0x04
15 #define CHGCONFIG2_REG 0x05
16 #define CHGCONFIG3_REG 0x06
17 #define WLEDCTRL1_REG 0x07
18 #define WLEDCTRL2_REG 0x08
19 #define MUXCTRL_REG 0x09
20 #define STATUS_REG 0x0a
21 #define PASSWORD_REG 0x0b
22 #define PGOOD_REG 0x0c
23 #define DEFPG_REG 0x0d
24 #define DEFDCDC1_REG 0x0e
25 #define DEFDCDC2_REG 0x0f
26 #define DEFDCDC3_REG 0x10
27 #define DEFSLEW_REG 0x11
28 #define DEFLDO1_REG 0x12
29 #define DEFLDO2_REG 0x13
30 #define DEFLS1_REG 0x14
31 #define DEFLS2_REG 0x15
32 #define ENABLE_REG 0x16
33 /* no documented register at 0x17 */
34 #define DEFUVLO_REG 0x18
45 * CHIP masks - CHIPID_REG[7:4]
47 #define TPS65217A_CHIP_MASK 0x70
48 #define TPS65217B_CHIP_MASK 0xf0
49 #define TPS65217C_CHIP_MASK 0xe0
50 #define TPS65217D_CHIP_MASK 0x60
53 * Interrupt Enable/Disable Bits/Masks - INT_REG[6:4]
54 * 0=Enable 1=Disable | Default mask: Disable ACM, USBM ~ Enable only PBM
56 #define PBM_INT_DIS_BIT 6
57 #define ACM_INT_DIS_BIT 5
58 #define USBM_INT_DIS_BIT 4
59 #define DEFAULT_INT_MASK ((1<<ACM_INT_DIS_BIT)|(1<<USBM_INT_DIS_BIT))
62 * Interrupt Status Bits - INT_REG[3:0]
67 #define PBI_MASK (1<<PBI_BIT)
70 * Power Off Bit - STATUS[7]
73 #define PWR_OFF_MASK (1<<OFF_BIT)
75 /* The TPS65217 is connected to the NMI pin of the AM335X on the BeagleBone and
76 * BeagleBone Black. That line is used to signal to the SoC that an interrupt
77 * has happened in the TPS65217. The NMI pin in turn generates an interrupt
78 * in the SoC which this driver will receive.
81 static int irq_hook_id
= 7;
82 static int irq_hook_kernel_id
= 7;
84 /* Only valid slave address for this device is 0x24 */
85 static i2c_addr_t valid_addrs
[2] = {
89 /* the bus that this device is on (counting starting at 1) */
92 /* slave address of the device */
93 static i2c_addr_t address
;
95 /* endpoint for the driver for the bus itself. */
96 static endpoint_t bus_endpoint
;
98 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
99 static struct log log
= {
101 .log_level
= LEVEL_INFO
,
102 .log_func
= default_log
105 /* Device Specific Functions */
106 static int check_revision(void);
107 static int enable_pwr_off(void);
108 static int intr_enable(void);
109 static int intr_handler(void);
110 static void do_shutdown(int how
);
112 /* SEF Related Function Prototypes */
113 static void sef_local_startup(void);
114 static int sef_cb_lu_state_save(int);
115 static int lu_state_restore(void);
116 static int sef_cb_init(int type
, sef_init_info_t
* info
);
124 r
= i2creg_read8(bus_endpoint
, address
, CHIPID_REG
, &chipid
);
126 log_warn(&log
, "Failed to read CHIPID\n");
130 switch (chipid
& 0xf0) {
131 case TPS65217A_CHIP_MASK
:
132 log_debug(&log
, "TPS65217A rev 1.%d\n", (chipid
& 0x0f));
134 case TPS65217B_CHIP_MASK
:
135 log_debug(&log
, "TPS65217B rev 1.%d\n", (chipid
& 0x0f));
137 case TPS65217C_CHIP_MASK
:
138 log_debug(&log
, "TPS65217C rev 1.%d\n", (chipid
& 0x0f));
140 case TPS65217D_CHIP_MASK
:
141 log_debug(&log
, "TPS65217D rev 1.%d\n", (chipid
& 0x0f));
144 log_warn(&log
, "Unexpected CHIPID: 0x%x\n", chipid
);
156 /* enable power off via the PWR_EN pin. just do the setup here.
157 * the kernel will do the work to toggle the pin when the
158 * system is ready to be powered off. Should be called during startup
159 * so that shutdown(8) can do power-off with reboot().
161 r
= i2creg_write8(bus_endpoint
, address
, STATUS_REG
, PWR_OFF_MASK
);
163 log_warn(&log
, "Cannot set power off mask.");
175 static int policy_set
= 0;
176 static int irq_enabled
= 0;
180 r
= sys_irqsetpolicy(irq
, 0, &irq_hook_kernel_id
);
184 log_warn(&log
, "Couldn't set irq policy\n");
188 if (policy_set
&& !irq_enabled
) {
189 r
= sys_irqenable(&irq_hook_kernel_id
);
193 log_warn(&log
, "Couldn't enable irq %d (hooked)\n",
199 /* Enable/Disable interrupts in the TPS65217 */
200 r
= i2creg_write8(bus_endpoint
, address
, INT_REG
, DEFAULT_INT_MASK
);
202 log_warn(&log
, "Failed to set interrupt mask.\n");
206 /* Read from the interrupt register to clear any pending interrupts */
207 r
= i2creg_read8(bus_endpoint
, address
, INT_REG
, &val
);
209 log_warn(&log
, "Failed to read interrupt register.\n");
223 /* read interrupt register to get interrupt that fired and clear it */
224 r
= i2creg_read8(bus_endpoint
, address
, INT_REG
, &val
);
226 log_warn(&log
, "Failed to read interrupt register.\n");
230 if ((val
& PBI_MASK
) != 0) {
231 log_info(&log
, "Power Button Pressed\n");
232 kill(1, SIGUSR1
); /* tell init to powerdwn */
236 /* re-enable interrupt */
237 r
= sys_irqenable(&irq_hook_kernel_id
);
239 log_warn(&log
, "Unable to renable IRQ (r=%d)\n", r
);
247 sef_cb_lu_state_save(int UNUSED(state
))
249 ds_publish_u32("bus", bus
, DSF_OVERWRITE
);
250 ds_publish_u32("address", address
, DSF_OVERWRITE
);
255 lu_state_restore(void)
257 /* Restore the state. */
260 ds_retrieve_u32("bus", &value
);
261 ds_delete_u32("bus");
264 ds_retrieve_u32("address", &value
);
265 ds_delete_u32("address");
266 address
= (int) value
;
272 sef_cb_init(int type
, sef_init_info_t
* UNUSED(info
))
276 if (type
== SEF_INIT_LU
) {
277 /* Restore the state. */
281 /* look-up the endpoint for the bus driver */
282 bus_endpoint
= i2cdriver_bus_endpoint(bus
);
283 if (bus_endpoint
== 0) {
284 log_warn(&log
, "Couldn't find bus driver.\n");
288 /* claim the device */
289 r
= i2cdriver_reserve_device(bus_endpoint
, address
);
291 log_warn(&log
, "Couldn't reserve device 0x%x (r=%d)\n",
296 /* check that the chip / rev is reasonable */
297 r
= check_revision();
299 /* prevent user from using the driver with a different chip */
300 log_warn(&log
, "Bad CHIPID\n");
304 /* enable interrupts */
307 log_warn(&log
, "Failed to enable interrupts.\n");
311 /* enable power-off pin so the kernel can cut power to the SoC */
314 if (type
!= SEF_INIT_LU
) {
316 /* sign up for updates about the i2c bus going down/up */
317 r
= i2cdriver_subscribe_bus_updates(bus
);
319 log_warn(&log
, "Couldn't subscribe to bus updates\n");
323 i2cdriver_announce(bus
);
324 log_debug(&log
, "announced\n");
331 sef_local_startup(void)
334 * Register init callbacks. Use the same function for all event types
336 sef_setcb_init_fresh(sef_cb_init
);
337 sef_setcb_init_lu(sef_cb_init
);
338 sef_setcb_init_restart(sef_cb_init
);
341 * Register live update callbacks.
343 /* Agree to update immediately when LU is requested in a valid state. */
344 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
345 /* Support live update starting from any standard state. */
346 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard
);
347 /* Register a custom routine to save the state. */
348 sef_setcb_lu_state_save(sef_cb_lu_state_save
);
350 /* Let SEF perform startup. */
355 main(int argc
, char *argv
[])
361 env_setargs(argc
, argv
);
363 r
= i2cdriver_env_parse(&bus
, &address
, valid_addrs
);
365 log_warn(&log
, "Expecting -args 'bus=X address=0xYY'\n");
366 log_warn(&log
, "Example -args 'bus=1 address=0x24'\n");
370 "Invalid slave address for device, expecting 0x24\n");
378 /* Receive Message */
379 r
= sef_receive_status(ANY
, &m
, &ipc_status
);
381 log_warn(&log
, "sef_receive_status() failed\n");
385 log_trace(&log
, "Got a message 0x%x from 0x%x\n", m
.m_type
,
388 if (is_ipc_notify(ipc_status
)) {
390 switch (m
.m_source
) {
393 /* bus driver changed state, update endpoint */
394 i2cdriver_handle_bus_update(&bus_endpoint
, bus
,
404 /* Do not reply to notifications. */
408 log_warn(&log
, "Ignoring message 0x%x from 0x%x\n", m
.m_type
,