1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Support for rfkill through the OLPC XO-1 laptop embedded controller 4 * 5 * Copyright (C) 2010 One Laptop per Child 6 */ 7 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/rfkill.h> 11 #include <linux/olpc-ec.h> 12 13 static bool card_blocked; 14 15 static int rfkill_set_block(void *data, bool blocked) 16 { 17 unsigned char cmd; 18 int r; 19 20 if (blocked == card_blocked) 21 return 0; 22 23 if (blocked) 24 cmd = EC_WLAN_ENTER_RESET; 25 else 26 cmd = EC_WLAN_LEAVE_RESET; 27 28 r = olpc_ec_cmd(cmd, NULL, 0, NULL, 0); 29 if (r == 0) 30 card_blocked = blocked; 31 32 return r; 33 } 34 35 static const struct rfkill_ops rfkill_ops = { 36 .set_block = rfkill_set_block, 37 }; 38 39 static int xo1_rfkill_probe(struct platform_device *pdev) 40 { 41 struct rfkill *rfk; 42 int r; 43 44 rfk = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_WLAN, 45 &rfkill_ops, NULL); 46 if (!rfk) 47 return -ENOMEM; 48 49 r = rfkill_register(rfk); 50 if (r) { 51 rfkill_destroy(rfk); 52 return r; 53 } 54 55 platform_set_drvdata(pdev, rfk); 56 return 0; 57 } 58 59 static void xo1_rfkill_remove(struct platform_device *pdev) 60 { 61 struct rfkill *rfk = platform_get_drvdata(pdev); 62 rfkill_unregister(rfk); 63 rfkill_destroy(rfk); 64 } 65 66 static struct platform_driver xo1_rfkill_driver = { 67 .driver = { 68 .name = "xo1-rfkill", 69 }, 70 .probe = xo1_rfkill_probe, 71 .remove = xo1_rfkill_remove, 72 }; 73 74 module_platform_driver(xo1_rfkill_driver); 75 76 MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); 77 MODULE_DESCRIPTION("OLPC XO-1 software RF kill switch"); 78 MODULE_LICENSE("GPL"); 79 MODULE_ALIAS("platform:xo1-rfkill"); 80