18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Allegro A8293 SEC driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "a8293.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct a8293_dev { 118c2ecf20Sopenharmony_ci struct i2c_client *client; 128c2ecf20Sopenharmony_ci u8 reg[2]; 138c2ecf20Sopenharmony_ci}; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int a8293_set_voltage(struct dvb_frontend *fe, 168c2ecf20Sopenharmony_ci enum fe_sec_voltage fe_sec_voltage) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct a8293_dev *dev = fe->sec_priv; 198c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 208c2ecf20Sopenharmony_ci int ret; 218c2ecf20Sopenharmony_ci u8 reg0, reg1; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci switch (fe_sec_voltage) { 268c2ecf20Sopenharmony_ci case SEC_VOLTAGE_OFF: 278c2ecf20Sopenharmony_ci /* ENB=0 */ 288c2ecf20Sopenharmony_ci reg0 = 0x10; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 318c2ecf20Sopenharmony_ci /* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/ 328c2ecf20Sopenharmony_ci reg0 = 0x31; 338c2ecf20Sopenharmony_ci break; 348c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 358c2ecf20Sopenharmony_ci /* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/ 368c2ecf20Sopenharmony_ci reg0 = 0x38; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci default: 398c2ecf20Sopenharmony_ci ret = -EINVAL; 408c2ecf20Sopenharmony_ci goto err; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci if (reg0 != dev->reg[0]) { 438c2ecf20Sopenharmony_ci ret = i2c_master_send(client, ®0, 1); 448c2ecf20Sopenharmony_ci if (ret < 0) 458c2ecf20Sopenharmony_ci goto err; 468c2ecf20Sopenharmony_ci dev->reg[0] = reg0; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* TMODE=0, TGATE=1 */ 508c2ecf20Sopenharmony_ci reg1 = 0x82; 518c2ecf20Sopenharmony_ci if (reg1 != dev->reg[1]) { 528c2ecf20Sopenharmony_ci ret = i2c_master_send(client, ®1, 1); 538c2ecf20Sopenharmony_ci if (ret < 0) 548c2ecf20Sopenharmony_ci goto err; 558c2ecf20Sopenharmony_ci dev->reg[1] = reg1; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci usleep_range(1500, 50000); 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_cierr: 618c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 628c2ecf20Sopenharmony_ci return ret; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int a8293_probe(struct i2c_client *client, 668c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct a8293_dev *dev; 698c2ecf20Sopenharmony_ci struct a8293_platform_data *pdata = client->dev.platform_data; 708c2ecf20Sopenharmony_ci struct dvb_frontend *fe = pdata->dvb_frontend; 718c2ecf20Sopenharmony_ci int ret; 728c2ecf20Sopenharmony_ci u8 buf[2]; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 758c2ecf20Sopenharmony_ci if (!dev) { 768c2ecf20Sopenharmony_ci ret = -ENOMEM; 778c2ecf20Sopenharmony_ci goto err; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci dev->client = client; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* check if the SEC is there */ 838c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, buf, 2); 848c2ecf20Sopenharmony_ci if (ret < 0) 858c2ecf20Sopenharmony_ci goto err_kfree; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* override frontend ops */ 888c2ecf20Sopenharmony_ci fe->ops.set_voltage = a8293_set_voltage; 898c2ecf20Sopenharmony_ci fe->sec_priv = dev; 908c2ecf20Sopenharmony_ci i2c_set_clientdata(client, dev); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci dev_info(&client->dev, "Allegro A8293 SEC successfully attached\n"); 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_cierr_kfree: 958c2ecf20Sopenharmony_ci kfree(dev); 968c2ecf20Sopenharmony_cierr: 978c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int a8293_remove(struct i2c_client *client) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct a8293_dev *dev = i2c_get_clientdata(client); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci kfree(dev); 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct i2c_device_id a8293_id_table[] = { 1128c2ecf20Sopenharmony_ci {"a8293", 0}, 1138c2ecf20Sopenharmony_ci {} 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, a8293_id_table); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct i2c_driver a8293_driver = { 1188c2ecf20Sopenharmony_ci .driver = { 1198c2ecf20Sopenharmony_ci .name = "a8293", 1208c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci .probe = a8293_probe, 1238c2ecf20Sopenharmony_ci .remove = a8293_remove, 1248c2ecf20Sopenharmony_ci .id_table = a8293_id_table, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cimodule_i2c_driver(a8293_driver); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 1308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allegro A8293 SEC driver"); 1318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 132