2019-06-01 10:08:35 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-04-12 17:34:31 +02:00
/*
* mchp23k256 . c
*
* Driver for Microchip 23 k256 SPI RAM chips
*
* Copyright © 2016 Andrew Lunn < andrew @ lunn . ch >
*/
# include <linux/device.h>
# include <linux/module.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/partitions.h>
# include <linux/mutex.h>
# include <linux/sched.h>
# include <linux/sizes.h>
# include <linux/spi/flash.h>
# include <linux/spi/spi.h>
2023-07-14 11:47:49 -06:00
# include <linux/of.h>
2017-04-12 17:34:31 +02:00
2017-06-02 15:21:19 +12:00
# define MAX_CMD_SIZE 4
struct mchp23_caps {
u8 addr_width ;
unsigned int size ;
} ;
2017-04-12 17:34:31 +02:00
struct mchp23k256_flash {
struct spi_device * spi ;
struct mutex lock ;
struct mtd_info mtd ;
2017-06-02 15:21:19 +12:00
const struct mchp23_caps * caps ;
2017-04-12 17:34:31 +02:00
} ;
# define MCHP23K256_CMD_WRITE_STATUS 0x01
# define MCHP23K256_CMD_WRITE 0x02
# define MCHP23K256_CMD_READ 0x03
# define MCHP23K256_MODE_SEQ BIT(6)
# define to_mchp23k256_flash(x) container_of(x, struct mchp23k256_flash, mtd)
2017-06-02 15:21:19 +12:00
static void mchp23k256_addr2cmd ( struct mchp23k256_flash * flash ,
unsigned int addr , u8 * cmd )
{
int i ;
/*
* Address is sent in big endian ( MSB first ) and we skip
* the first entry of the cmd array which contains the cmd
* opcode .
*/
for ( i = flash - > caps - > addr_width ; i > 0 ; i - - , addr > > = 8 )
cmd [ i ] = addr ;
}
static int mchp23k256_cmdsz ( struct mchp23k256_flash * flash )
{
return 1 + flash - > caps - > addr_width ;
}
2017-04-12 17:34:31 +02:00
static int mchp23k256_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const unsigned char * buf )
{
struct mchp23k256_flash * flash = to_mchp23k256_flash ( mtd ) ;
struct spi_transfer transfer [ 2 ] = { } ;
struct spi_message message ;
2017-06-02 15:21:19 +12:00
unsigned char command [ MAX_CMD_SIZE ] ;
2019-10-30 12:39:57 +01:00
int ret , cmd_len ;
2017-04-12 17:34:31 +02:00
spi_message_init ( & message ) ;
2019-10-30 12:39:57 +01:00
cmd_len = mchp23k256_cmdsz ( flash ) ;
2017-04-12 17:34:31 +02:00
command [ 0 ] = MCHP23K256_CMD_WRITE ;
2017-06-02 15:21:19 +12:00
mchp23k256_addr2cmd ( flash , to , command ) ;
2017-04-12 17:34:31 +02:00
transfer [ 0 ] . tx_buf = command ;
2019-10-30 12:39:57 +01:00
transfer [ 0 ] . len = cmd_len ;
2017-04-12 17:34:31 +02:00
spi_message_add_tail ( & transfer [ 0 ] , & message ) ;
transfer [ 1 ] . tx_buf = buf ;
transfer [ 1 ] . len = len ;
spi_message_add_tail ( & transfer [ 1 ] , & message ) ;
mutex_lock ( & flash - > lock ) ;
2017-12-10 16:19:56 +01:00
ret = spi_sync ( flash - > spi , & message ) ;
mutex_unlock ( & flash - > lock ) ;
if ( ret )
return ret ;
2017-04-12 17:34:31 +02:00
2019-10-30 12:39:57 +01:00
if ( retlen & & message . actual_length > cmd_len )
* retlen + = message . actual_length - cmd_len ;
2017-04-12 17:34:31 +02:00
return 0 ;
}
static int mchp23k256_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , unsigned char * buf )
{
struct mchp23k256_flash * flash = to_mchp23k256_flash ( mtd ) ;
struct spi_transfer transfer [ 2 ] = { } ;
struct spi_message message ;
2017-06-02 15:21:19 +12:00
unsigned char command [ MAX_CMD_SIZE ] ;
2019-10-30 12:39:57 +01:00
int ret , cmd_len ;
2017-04-12 17:34:31 +02:00
spi_message_init ( & message ) ;
2019-10-30 12:39:57 +01:00
cmd_len = mchp23k256_cmdsz ( flash ) ;
2017-04-12 17:34:31 +02:00
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
command [ 0 ] = MCHP23K256_CMD_READ ;
2017-06-02 15:21:19 +12:00
mchp23k256_addr2cmd ( flash , from , command ) ;
2017-04-12 17:34:31 +02:00
transfer [ 0 ] . tx_buf = command ;
2019-10-30 12:39:57 +01:00
transfer [ 0 ] . len = cmd_len ;
2017-04-12 17:34:31 +02:00
spi_message_add_tail ( & transfer [ 0 ] , & message ) ;
transfer [ 1 ] . rx_buf = buf ;
transfer [ 1 ] . len = len ;
spi_message_add_tail ( & transfer [ 1 ] , & message ) ;
mutex_lock ( & flash - > lock ) ;
2017-12-10 16:19:56 +01:00
ret = spi_sync ( flash - > spi , & message ) ;
mutex_unlock ( & flash - > lock ) ;
if ( ret )
return ret ;
2017-04-12 17:34:31 +02:00
2019-10-30 12:39:57 +01:00
if ( retlen & & message . actual_length > cmd_len )
* retlen + = message . actual_length - cmd_len ;
2017-04-12 17:34:31 +02:00
return 0 ;
}
/*
* Set the device into sequential mode . This allows read / writes to the
* entire SRAM in a single operation
*/
static int mchp23k256_set_mode ( struct spi_device * spi )
{
struct spi_transfer transfer = { } ;
struct spi_message message ;
unsigned char command [ 2 ] ;
spi_message_init ( & message ) ;
command [ 0 ] = MCHP23K256_CMD_WRITE_STATUS ;
command [ 1 ] = MCHP23K256_MODE_SEQ ;
transfer . tx_buf = command ;
transfer . len = sizeof ( command ) ;
spi_message_add_tail ( & transfer , & message ) ;
return spi_sync ( spi , & message ) ;
}
2017-06-02 15:21:19 +12:00
static const struct mchp23_caps mchp23k256_caps = {
. size = SZ_32K ,
. addr_width = 2 ,
} ;
static const struct mchp23_caps mchp23lcv1024_caps = {
. size = SZ_128K ,
. addr_width = 3 ,
} ;
2017-04-12 17:34:31 +02:00
static int mchp23k256_probe ( struct spi_device * spi )
{
struct mchp23k256_flash * flash ;
struct flash_platform_data * data ;
int err ;
flash = devm_kzalloc ( & spi - > dev , sizeof ( * flash ) , GFP_KERNEL ) ;
if ( ! flash )
return - ENOMEM ;
flash - > spi = spi ;
mutex_init ( & flash - > lock ) ;
spi_set_drvdata ( spi , flash ) ;
err = mchp23k256_set_mode ( spi ) ;
if ( err )
return err ;
data = dev_get_platdata ( & spi - > dev ) ;
2017-06-02 15:21:19 +12:00
flash - > caps = of_device_get_match_data ( & spi - > dev ) ;
if ( ! flash - > caps )
flash - > caps = & mchp23k256_caps ;
2017-06-02 15:21:18 +12:00
mtd_set_of_node ( & flash - > mtd , spi - > dev . of_node ) ;
2017-04-12 17:34:31 +02:00
flash - > mtd . dev . parent = & spi - > dev ;
flash - > mtd . type = MTD_RAM ;
flash - > mtd . flags = MTD_CAP_RAM ;
flash - > mtd . writesize = 1 ;
2017-06-02 15:21:19 +12:00
flash - > mtd . size = flash - > caps - > size ;
2017-04-12 17:34:31 +02:00
flash - > mtd . _read = mchp23k256_read ;
flash - > mtd . _write = mchp23k256_write ;
2017-05-25 11:49:13 +12:00
err = mtd_device_register ( & flash - > mtd , data ? data - > parts : NULL ,
data ? data - > nr_parts : 0 ) ;
2017-04-12 17:34:31 +02:00
if ( err )
return err ;
return 0 ;
}
2022-01-23 18:52:01 +01:00
static void mchp23k256_remove ( struct spi_device * spi )
2017-04-12 17:34:31 +02:00
{
struct mchp23k256_flash * flash = spi_get_drvdata ( spi ) ;
2021-11-08 10:31:50 +01:00
WARN_ON ( mtd_device_unregister ( & flash - > mtd ) ) ;
2017-04-12 17:34:31 +02:00
}
2017-05-25 11:49:12 +12:00
static const struct of_device_id mchp23k256_of_table [ ] = {
2017-06-02 15:21:19 +12:00
{
. compatible = " microchip,mchp23k256 " ,
. data = & mchp23k256_caps ,
} ,
{
. compatible = " microchip,mchp23lcv1024 " ,
. data = & mchp23lcv1024_caps ,
} ,
2017-05-25 11:49:12 +12:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , mchp23k256_of_table ) ;
2022-02-02 14:34:03 +00:00
static const struct spi_device_id mchp23k256_spi_ids [ ] = {
{
. name = " mchp23k256 " ,
. driver_data = ( kernel_ulong_t ) & mchp23k256_caps ,
} ,
{
. name = " mchp23lcv1024 " ,
. driver_data = ( kernel_ulong_t ) & mchp23lcv1024_caps ,
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , mchp23k256_spi_ids ) ;
2017-04-12 17:34:31 +02:00
static struct spi_driver mchp23k256_driver = {
. driver = {
. name = " mchp23k256 " ,
mtd: Fix misuses of of_match_ptr()
of_match_ptr() either expands to NULL if !CONFIG_OF, or is transparent
otherwise. There are several drivers using this macro which keep their
of_device_id array enclosed within an #ifdef CONFIG_OF check, these are
considered fine. However, When misused, the of_device_id array pointed
by this macro will produce a warning because it is finally unused when
compiled without OF support.
A number of fixes are possible:
- Always depend on CONFIG_OF, but this will not always work and may
break boards.
- Enclose the compatible array by #ifdef's, this may save a bit of
memory but will reduce build coverage.
- Tell the compiler the array may be unused, if this can be avoided,
let's not do this.
- Just drop the macro, setting the of_device_id array for a non OF
enabled platform is not an issue, it will just be unused.
The latter solution seems the more appropriate, so let's use it.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Paul Cercueil <paul@crapouillou.net>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: Pratyush Yadav <p.yadav@ti.com>
Link: https://lore.kernel.org/linux-mtd/20220127110631.1064705-1-miquel.raynal@bootlin.com
2022-01-27 12:06:31 +01:00
. of_match_table = mchp23k256_of_table ,
2017-04-12 17:34:31 +02:00
} ,
. probe = mchp23k256_probe ,
. remove = mchp23k256_remove ,
2022-02-02 14:34:03 +00:00
. id_table = mchp23k256_spi_ids ,
2017-04-12 17:34:31 +02:00
} ;
module_spi_driver ( mchp23k256_driver ) ;
MODULE_DESCRIPTION ( " MTD SPI driver for MCHP23K256 RAM chips " ) ;
MODULE_AUTHOR ( " Andrew Lunn <andre@lunn.ch> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " spi:mchp23k256 " ) ;