2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-08-13 04:18:59 +03:00
/*
* Qualcomm Wireless Connectivity Subsystem Iris driver
*
* Copyright ( C ) 2016 Linaro Ltd
* Copyright ( C ) 2014 Sony Mobile Communications AB
* Copyright ( c ) 2012 - 2013 , The Linux Foundation . All rights reserved .
*/
# include <linux/clk.h>
# include <linux/kernel.h>
# include <linux/module.h>
2023-07-14 20:49:33 +03:00
# include <linux/of.h>
2016-08-13 04:18:59 +03:00
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/regulator/consumer.h>
# include "qcom_wcnss.h"
struct qcom_iris {
2021-03-12 03:22:51 +03:00
struct device dev ;
2016-08-13 04:18:59 +03:00
struct clk * xo_clk ;
struct regulator_bulk_data * vregs ;
size_t num_vregs ;
} ;
struct iris_data {
const struct wcnss_vreg_info * vregs ;
size_t num_vregs ;
bool use_48mhz_xo ;
} ;
static const struct iris_data wcn3620_data = {
. vregs = ( struct wcnss_vreg_info [ ] ) {
{ " vddxo " , 1800000 , 1800000 , 10000 } ,
{ " vddrfa " , 1300000 , 1300000 , 100000 } ,
{ " vddpa " , 3300000 , 3300000 , 515000 } ,
{ " vdddig " , 1800000 , 1800000 , 10000 } ,
} ,
. num_vregs = 4 ,
. use_48mhz_xo = false ,
} ;
static const struct iris_data wcn3660_data = {
. vregs = ( struct wcnss_vreg_info [ ] ) {
{ " vddxo " , 1800000 , 1800000 , 10000 } ,
{ " vddrfa " , 1300000 , 1300000 , 100000 } ,
{ " vddpa " , 2900000 , 3000000 , 515000 } ,
{ " vdddig " , 1200000 , 1225000 , 10000 } ,
} ,
. num_vregs = 4 ,
. use_48mhz_xo = true ,
} ;
static const struct iris_data wcn3680_data = {
. vregs = ( struct wcnss_vreg_info [ ] ) {
{ " vddxo " , 1800000 , 1800000 , 10000 } ,
{ " vddrfa " , 1300000 , 1300000 , 100000 } ,
{ " vddpa " , 3300000 , 3300000 , 515000 } ,
{ " vdddig " , 1800000 , 1800000 , 10000 } ,
} ,
. num_vregs = 4 ,
. use_48mhz_xo = true ,
} ;
int qcom_iris_enable ( struct qcom_iris * iris )
{
int ret ;
ret = regulator_bulk_enable ( iris - > num_vregs , iris - > vregs ) ;
if ( ret )
return ret ;
ret = clk_prepare_enable ( iris - > xo_clk ) ;
if ( ret ) {
2021-03-12 03:22:51 +03:00
dev_err ( & iris - > dev , " failed to enable xo clk \n " ) ;
2016-08-13 04:18:59 +03:00
goto disable_regulators ;
}
return 0 ;
disable_regulators :
regulator_bulk_disable ( iris - > num_vregs , iris - > vregs ) ;
return ret ;
}
void qcom_iris_disable ( struct qcom_iris * iris )
{
clk_disable_unprepare ( iris - > xo_clk ) ;
regulator_bulk_disable ( iris - > num_vregs , iris - > vregs ) ;
}
2021-03-12 03:22:51 +03:00
static const struct of_device_id iris_of_match [ ] = {
{ . compatible = " qcom,wcn3620 " , . data = & wcn3620_data } ,
{ . compatible = " qcom,wcn3660 " , . data = & wcn3660_data } ,
{ . compatible = " qcom,wcn3660b " , . data = & wcn3680_data } ,
{ . compatible = " qcom,wcn3680 " , . data = & wcn3680_data } ,
{ }
} ;
static void qcom_iris_release ( struct device * dev )
{
struct qcom_iris * iris = container_of ( dev , struct qcom_iris , dev ) ;
of_node_put ( iris - > dev . of_node ) ;
kfree ( iris ) ;
}
struct qcom_iris * qcom_iris_probe ( struct device * parent , bool * use_48mhz_xo )
2016-08-13 04:18:59 +03:00
{
2021-03-12 03:22:51 +03:00
const struct of_device_id * match ;
2016-08-13 04:18:59 +03:00
const struct iris_data * data ;
2021-03-12 03:22:51 +03:00
struct device_node * of_node ;
2016-08-13 04:18:59 +03:00
struct qcom_iris * iris ;
int ret ;
int i ;
2021-03-12 03:22:51 +03:00
of_node = of_get_child_by_name ( parent - > of_node , " iris " ) ;
if ( ! of_node ) {
dev_err ( parent , " No child node \" iris \" found \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
iris = kzalloc ( sizeof ( * iris ) , GFP_KERNEL ) ;
if ( ! iris ) {
of_node_put ( of_node ) ;
return ERR_PTR ( - ENOMEM ) ;
}
device_initialize ( & iris - > dev ) ;
iris - > dev . parent = parent ;
iris - > dev . release = qcom_iris_release ;
iris - > dev . of_node = of_node ;
dev_set_name ( & iris - > dev , " %s.iris " , dev_name ( parent ) ) ;
ret = device_add ( & iris - > dev ) ;
if ( ret ) {
put_device ( & iris - > dev ) ;
return ERR_PTR ( ret ) ;
}
match = of_match_device ( iris_of_match , & iris - > dev ) ;
if ( ! match ) {
dev_err ( & iris - > dev , " no matching compatible for iris \n " ) ;
ret = - EINVAL ;
goto err_device_del ;
}
2016-08-13 04:18:59 +03:00
2021-03-12 03:22:51 +03:00
data = match - > data ;
2016-08-13 04:18:59 +03:00
2021-03-12 03:22:51 +03:00
iris - > xo_clk = devm_clk_get ( & iris - > dev , " xo " ) ;
2016-08-13 04:18:59 +03:00
if ( IS_ERR ( iris - > xo_clk ) ) {
2021-03-12 03:22:51 +03:00
ret = PTR_ERR ( iris - > xo_clk ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( & iris - > dev , " failed to acquire xo clk \n " ) ;
goto err_device_del ;
2016-08-13 04:18:59 +03:00
}
iris - > num_vregs = data - > num_vregs ;
2021-03-12 03:22:51 +03:00
iris - > vregs = devm_kcalloc ( & iris - > dev ,
2016-08-13 04:18:59 +03:00
iris - > num_vregs ,
sizeof ( struct regulator_bulk_data ) ,
GFP_KERNEL ) ;
2021-03-12 03:22:51 +03:00
if ( ! iris - > vregs ) {
ret = - ENOMEM ;
goto err_device_del ;
}
2016-08-13 04:18:59 +03:00
for ( i = 0 ; i < iris - > num_vregs ; i + + )
iris - > vregs [ i ] . supply = data - > vregs [ i ] . name ;
2021-03-12 03:22:51 +03:00
ret = devm_regulator_bulk_get ( & iris - > dev , iris - > num_vregs , iris - > vregs ) ;
2016-08-13 04:18:59 +03:00
if ( ret ) {
2021-03-12 03:22:51 +03:00
dev_err ( & iris - > dev , " failed to get regulators \n " ) ;
goto err_device_del ;
2016-08-13 04:18:59 +03:00
}
for ( i = 0 ; i < iris - > num_vregs ; i + + ) {
if ( data - > vregs [ i ] . max_voltage )
regulator_set_voltage ( iris - > vregs [ i ] . consumer ,
data - > vregs [ i ] . min_voltage ,
data - > vregs [ i ] . max_voltage ) ;
if ( data - > vregs [ i ] . load_uA )
regulator_set_load ( iris - > vregs [ i ] . consumer ,
data - > vregs [ i ] . load_uA ) ;
}
2021-03-12 03:22:51 +03:00
* use_48mhz_xo = data - > use_48mhz_xo ;
2016-08-13 04:18:59 +03:00
2021-03-12 03:22:51 +03:00
return iris ;
2016-08-13 04:18:59 +03:00
2021-03-12 03:22:51 +03:00
err_device_del :
device_del ( & iris - > dev ) ;
2016-08-13 04:18:59 +03:00
2021-03-12 03:22:51 +03:00
return ERR_PTR ( ret ) ;
2016-08-13 04:18:59 +03:00
}
2021-03-12 03:22:51 +03:00
void qcom_iris_remove ( struct qcom_iris * iris )
{
device_del ( & iris - > dev ) ;
}