2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-11-01 05:32:08 +03:00
/*
* Copyright ( C ) 2017 Spreadtrum Communications Inc .
*/
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mfd/core.h>
2020-06-23 12:08:41 +03:00
# include <linux/mfd/sc27xx-pmic.h>
2017-11-01 05:32:08 +03:00
# include <linux/of_device.h>
2020-06-19 12:09:14 +03:00
# include <linux/of_platform.h>
2017-11-01 05:32:08 +03:00
# include <linux/regmap.h>
# include <linux/spi/spi.h>
2020-02-17 05:26:16 +03:00
# include <uapi/linux/usb/charger.h>
2017-11-01 05:32:08 +03:00
# define SPRD_PMIC_INT_MASK_STATUS 0x0
# define SPRD_PMIC_INT_RAW_STATUS 0x4
# define SPRD_PMIC_INT_EN 0x8
2021-09-15 12:17:26 +03:00
# define SPRD_SC2730_IRQ_BASE 0x80
# define SPRD_SC2730_IRQ_NUMS 10
# define SPRD_SC2730_CHG_DET 0x1b9c
2017-11-01 05:32:08 +03:00
# define SPRD_SC2731_IRQ_BASE 0x140
# define SPRD_SC2731_IRQ_NUMS 16
2020-02-17 05:26:16 +03:00
# define SPRD_SC2731_CHG_DET 0xedc
/* PMIC charger detection definition */
# define SPRD_PMIC_CHG_DET_DELAY_US 200000
# define SPRD_PMIC_CHG_DET_TIMEOUT 2000000
# define SPRD_PMIC_CHG_DET_DONE BIT(11)
# define SPRD_PMIC_SDP_TYPE BIT(7)
# define SPRD_PMIC_DCP_TYPE BIT(6)
# define SPRD_PMIC_CDP_TYPE BIT(5)
# define SPRD_PMIC_CHG_TYPE_MASK GENMASK(7, 5)
2017-11-01 05:32:08 +03:00
struct sprd_pmic {
struct regmap * regmap ;
struct device * dev ;
struct regmap_irq * irqs ;
struct regmap_irq_chip irq_chip ;
struct regmap_irq_chip_data * irq_data ;
2020-02-17 05:26:16 +03:00
const struct sprd_pmic_data * pdata ;
2017-11-01 05:32:08 +03:00
int irq ;
} ;
struct sprd_pmic_data {
u32 irq_base ;
u32 num_irqs ;
2020-02-17 05:26:16 +03:00
u32 charger_det ;
2017-11-01 05:32:08 +03:00
} ;
/*
* Since different PMICs of SC27xx series can have different interrupt
* base address and irq number , we should save irq number and irq base
* in the device data structure .
*/
2021-09-15 12:17:26 +03:00
static const struct sprd_pmic_data sc2730_data = {
. irq_base = SPRD_SC2730_IRQ_BASE ,
. num_irqs = SPRD_SC2730_IRQ_NUMS ,
. charger_det = SPRD_SC2730_CHG_DET ,
} ;
2017-11-01 05:32:08 +03:00
static const struct sprd_pmic_data sc2731_data = {
. irq_base = SPRD_SC2731_IRQ_BASE ,
. num_irqs = SPRD_SC2731_IRQ_NUMS ,
2020-02-17 05:26:16 +03:00
. charger_det = SPRD_SC2731_CHG_DET ,
2017-11-01 05:32:08 +03:00
} ;
2020-02-17 05:26:16 +03:00
enum usb_charger_type sprd_pmic_detect_charger_type ( struct device * dev )
{
struct spi_device * spi = to_spi_device ( dev ) ;
struct sprd_pmic * ddata = spi_get_drvdata ( spi ) ;
const struct sprd_pmic_data * pdata = ddata - > pdata ;
enum usb_charger_type type ;
u32 val ;
int ret ;
ret = regmap_read_poll_timeout ( ddata - > regmap , pdata - > charger_det , val ,
( val & SPRD_PMIC_CHG_DET_DONE ) ,
SPRD_PMIC_CHG_DET_DELAY_US ,
SPRD_PMIC_CHG_DET_TIMEOUT ) ;
if ( ret ) {
dev_err ( & spi - > dev , " failed to detect charger type \n " ) ;
return UNKNOWN_TYPE ;
}
switch ( val & SPRD_PMIC_CHG_TYPE_MASK ) {
case SPRD_PMIC_CDP_TYPE :
type = CDP_TYPE ;
break ;
case SPRD_PMIC_DCP_TYPE :
type = DCP_TYPE ;
break ;
case SPRD_PMIC_SDP_TYPE :
type = SDP_TYPE ;
break ;
default :
type = UNKNOWN_TYPE ;
break ;
}
return type ;
}
EXPORT_SYMBOL_GPL ( sprd_pmic_detect_charger_type ) ;
2017-11-01 05:32:08 +03:00
static int sprd_pmic_spi_write ( void * context , const void * data , size_t count )
{
struct device * dev = context ;
struct spi_device * spi = to_spi_device ( dev ) ;
return spi_write ( spi , data , count ) ;
}
static int sprd_pmic_spi_read ( void * context ,
const void * reg , size_t reg_size ,
void * val , size_t val_size )
{
struct device * dev = context ;
struct spi_device * spi = to_spi_device ( dev ) ;
u32 rx_buf [ 2 ] = { 0 } ;
int ret ;
/* Now we only support one PMIC register to read every time. */
if ( reg_size ! = sizeof ( u32 ) | | val_size ! = sizeof ( u32 ) )
return - EINVAL ;
/* Copy address to read from into first element of SPI buffer. */
memcpy ( rx_buf , reg , sizeof ( u32 ) ) ;
ret = spi_read ( spi , rx_buf , 1 ) ;
if ( ret < 0 )
return ret ;
memcpy ( val , rx_buf , val_size ) ;
return 0 ;
}
static struct regmap_bus sprd_pmic_regmap = {
. write = sprd_pmic_spi_write ,
. read = sprd_pmic_spi_read ,
. reg_format_endian_default = REGMAP_ENDIAN_NATIVE ,
. val_format_endian_default = REGMAP_ENDIAN_NATIVE ,
} ;
static const struct regmap_config sprd_pmic_config = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. max_register = 0xffff ,
} ;
static int sprd_pmic_probe ( struct spi_device * spi )
{
struct sprd_pmic * ddata ;
const struct sprd_pmic_data * pdata ;
int ret , i ;
pdata = of_device_get_match_data ( & spi - > dev ) ;
if ( ! pdata ) {
dev_err ( & spi - > dev , " No matching driver data found \n " ) ;
return - EINVAL ;
}
ddata = devm_kzalloc ( & spi - > dev , sizeof ( * ddata ) , GFP_KERNEL ) ;
if ( ! ddata )
return - ENOMEM ;
ddata - > regmap = devm_regmap_init ( & spi - > dev , & sprd_pmic_regmap ,
& spi - > dev , & sprd_pmic_config ) ;
if ( IS_ERR ( ddata - > regmap ) ) {
ret = PTR_ERR ( ddata - > regmap ) ;
dev_err ( & spi - > dev , " Failed to allocate register map %d \n " , ret ) ;
return ret ;
}
spi_set_drvdata ( spi , ddata ) ;
ddata - > dev = & spi - > dev ;
ddata - > irq = spi - > irq ;
2020-02-17 05:26:16 +03:00
ddata - > pdata = pdata ;
2017-11-01 05:32:08 +03:00
ddata - > irq_chip . name = dev_name ( & spi - > dev ) ;
ddata - > irq_chip . status_base =
pdata - > irq_base + SPRD_PMIC_INT_MASK_STATUS ;
2022-11-12 18:18:31 +03:00
ddata - > irq_chip . unmask_base = pdata - > irq_base + SPRD_PMIC_INT_EN ;
2017-11-01 05:32:08 +03:00
ddata - > irq_chip . ack_base = 0 ;
ddata - > irq_chip . num_regs = 1 ;
ddata - > irq_chip . num_irqs = pdata - > num_irqs ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
ddata - > irqs = devm_kcalloc ( & spi - > dev ,
pdata - > num_irqs , sizeof ( struct regmap_irq ) ,
GFP_KERNEL ) ;
2017-11-01 05:32:08 +03:00
if ( ! ddata - > irqs )
return - ENOMEM ;
ddata - > irq_chip . irqs = ddata - > irqs ;
2020-06-25 11:39:11 +03:00
for ( i = 0 ; i < pdata - > num_irqs ; i + + )
ddata - > irqs [ i ] . mask = BIT ( i ) ;
2017-11-01 05:32:08 +03:00
ret = devm_regmap_add_irq_chip ( & spi - > dev , ddata - > regmap , ddata - > irq ,
2020-08-18 06:41:58 +03:00
IRQF_ONESHOT , 0 ,
2017-11-01 05:32:08 +03:00
& ddata - > irq_chip , & ddata - > irq_data ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed to add PMIC irq chip %d \n " , ret ) ;
return ret ;
}
2020-06-19 12:09:14 +03:00
ret = devm_of_platform_populate ( & spi - > dev ) ;
2017-11-01 05:32:08 +03:00
if ( ret ) {
2020-06-19 12:09:14 +03:00
dev_err ( & spi - > dev , " Failed to populate sub-devices %d \n " , ret ) ;
2017-11-01 05:32:08 +03:00
return ret ;
}
2020-08-18 06:41:58 +03:00
device_init_wakeup ( & spi - > dev , true ) ;
2017-11-01 05:32:08 +03:00
return 0 ;
}
2020-08-18 06:41:58 +03:00
static int sprd_pmic_suspend ( struct device * dev )
{
struct sprd_pmic * ddata = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
enable_irq_wake ( ddata - > irq ) ;
return 0 ;
}
static int sprd_pmic_resume ( struct device * dev )
{
struct sprd_pmic * ddata = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
disable_irq_wake ( ddata - > irq ) ;
return 0 ;
}
2022-10-23 12:48:47 +03:00
static DEFINE_SIMPLE_DEV_PM_OPS ( sprd_pmic_pm_ops ,
sprd_pmic_suspend , sprd_pmic_resume ) ;
2020-08-18 06:41:58 +03:00
2017-11-01 05:32:08 +03:00
static const struct of_device_id sprd_pmic_match [ ] = {
2021-09-15 12:17:26 +03:00
{ . compatible = " sprd,sc2730 " , . data = & sc2730_data } ,
2022-04-27 10:52:12 +03:00
{ . compatible = " sprd,sc2731 " , . data = & sc2731_data } ,
2017-11-01 05:32:08 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , sprd_pmic_match ) ;
2021-09-24 17:33:47 +03:00
static const struct spi_device_id sprd_pmic_spi_ids [ ] = {
2022-04-25 16:24:10 +03:00
{ . name = " sc2730 " , . driver_data = ( unsigned long ) & sc2730_data } ,
2022-04-27 10:52:12 +03:00
{ . name = " sc2731 " , . driver_data = ( unsigned long ) & sc2731_data } ,
2021-09-24 17:33:47 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , sprd_pmic_spi_ids ) ;
2017-11-01 05:32:08 +03:00
static struct spi_driver sprd_pmic_driver = {
. driver = {
. name = " sc27xx-pmic " ,
. of_match_table = sprd_pmic_match ,
2022-10-23 12:48:47 +03:00
. pm = pm_sleep_ptr ( & sprd_pmic_pm_ops ) ,
2017-11-01 05:32:08 +03:00
} ,
. probe = sprd_pmic_probe ,
2021-09-24 17:33:47 +03:00
. id_table = sprd_pmic_spi_ids ,
2017-11-01 05:32:08 +03:00
} ;
static int __init sprd_pmic_init ( void )
{
return spi_register_driver ( & sprd_pmic_driver ) ;
}
subsys_initcall ( sprd_pmic_init ) ;
static void __exit sprd_pmic_exit ( void )
{
spi_unregister_driver ( & sprd_pmic_driver ) ;
}
module_exit ( sprd_pmic_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Spreadtrum SC27xx PMICs driver " ) ;
MODULE_AUTHOR ( " Baolin Wang <baolin.wang@spreadtrum.com> " ) ;