18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for rfkill through the OLPC XO-1 laptop embedded controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 One Laptop per Child 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 108c2ecf20Sopenharmony_ci#include <linux/rfkill.h> 118c2ecf20Sopenharmony_ci#include <linux/olpc-ec.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic bool card_blocked; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int rfkill_set_block(void *data, bool blocked) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci unsigned char cmd; 188c2ecf20Sopenharmony_ci int r; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (blocked == card_blocked) 218c2ecf20Sopenharmony_ci return 0; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (blocked) 248c2ecf20Sopenharmony_ci cmd = EC_WLAN_ENTER_RESET; 258c2ecf20Sopenharmony_ci else 268c2ecf20Sopenharmony_ci cmd = EC_WLAN_LEAVE_RESET; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci r = olpc_ec_cmd(cmd, NULL, 0, NULL, 0); 298c2ecf20Sopenharmony_ci if (r == 0) 308c2ecf20Sopenharmony_ci card_blocked = blocked; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return r; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const struct rfkill_ops rfkill_ops = { 368c2ecf20Sopenharmony_ci .set_block = rfkill_set_block, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int xo1_rfkill_probe(struct platform_device *pdev) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct rfkill *rfk; 428c2ecf20Sopenharmony_ci int r; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci rfk = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_WLAN, 458c2ecf20Sopenharmony_ci &rfkill_ops, NULL); 468c2ecf20Sopenharmony_ci if (!rfk) 478c2ecf20Sopenharmony_ci return -ENOMEM; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci r = rfkill_register(rfk); 508c2ecf20Sopenharmony_ci if (r) { 518c2ecf20Sopenharmony_ci rfkill_destroy(rfk); 528c2ecf20Sopenharmony_ci return r; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rfk); 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int xo1_rfkill_remove(struct platform_device *pdev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct rfkill *rfk = platform_get_drvdata(pdev); 628c2ecf20Sopenharmony_ci rfkill_unregister(rfk); 638c2ecf20Sopenharmony_ci rfkill_destroy(rfk); 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct platform_driver xo1_rfkill_driver = { 688c2ecf20Sopenharmony_ci .driver = { 698c2ecf20Sopenharmony_ci .name = "xo1-rfkill", 708c2ecf20Sopenharmony_ci }, 718c2ecf20Sopenharmony_ci .probe = xo1_rfkill_probe, 728c2ecf20Sopenharmony_ci .remove = xo1_rfkill_remove, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cimodule_platform_driver(xo1_rfkill_driver); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); 788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 798c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:xo1-rfkill"); 80